线段树好题! P2824 [HEOI2016/TJOI2016]排序 题解

题目传送门

前言

线段树好题!!!!
咕咕了挺久的一道题目,很早之前就想写了,今天终于找了个时间A掉了。

题意

给定一个 \(1\)\(n\) 的排列,有 \(m\) 次操作,分两种类型。
1.0 l r表示将下标在 \([l, r]\) 区间中的数升序排序。
2.1 l r表示将下标在 \([l, r]\) 区间中的数降序排序。
给定一个数 \(q\) 询问最后 \(q\) 位置上的数。

\(Solution\)

看到数据范围,发现前 \(30\) 分是可以暴力的,这里不多赘述。
注意到 \(n,m\leqslant 10^5\) ,优先考虑 \(O(nlogn)\)\(O(n \sqrt n)\) 做法。对一个序列进行操作,自然想到,线段树,但是线段树不支持区间排序那怎么办呢。
考虑对一段 \(01\) 串做排序,显然排完序后会变成 \(00011\)\(11100\) 这种形式,可以用线段树的区间推平和求和操作来完成。
但是原序列不是 \(01\) 串,我们就要把它转换成 \(01\) 串。
可以选取一个基准数,让原序列大于等于这个数的都变成 \(1\) ,其他的都是 \(0\) 就能解决这个问题了。
如果操作完之后 \(q\) 上的是 \(1\) ,说明答案至少是大于等于这个基准数的,所以二分就行了。
总复杂度 \(O(n log^2n)\)

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5, INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
int n, m, pos;
int a[N];
struct question
{
	int op, l, r;
} Q[N];
struct segment_tree
{
	int l, r, val, tag;
	#define l(x) tr[x].l
	#define r(x) tr[x].r
	#define val(x) tr[x].val
	#define tag(x) tr[x].tag
} tr[N << 2];
void pushup(int x)
{
	val(x) = val(x << 1) + val(x << 1 | 1);
}
void pushdown(int x)
{
	if(tag(x) == -1) return;
	val(x << 1) = (r(x << 1) - l(x << 1) + 1) * tag(x);
	tag(x << 1) = tag(x);
	val(x << 1 | 1) = (r(x << 1 | 1) - l(x << 1 | 1) + 1) * tag(x);
	tag(x << 1 | 1) = tag(x);
	tag(x) = -1;
}
void build(int l, int r, int x, int v)
{
	l(x) = l, r(x) = r, tag(x) = -1, val(x) = 0;
	if(l == r)
	{
		val(x) = (a[l] >= v);
		return;
	}
	int mid = l + r >> 1;
	build(l, mid, x << 1, v), build(mid + 1, r, x << 1 | 1, v);
	pushup(x);
}
void update(int l, int r, int x, int v)
{
	if(l <= l(x) && r(x) <= r)
	{
		tag(x) = v;
		val(x) = (r(x) - l(x) + 1) * v;
		return;
	}
	pushdown(x);
	int mid = l(x) + r(x) >> 1;
	if(l <= mid) update(l, r, x << 1, v);
	if(r > mid) update(l, r, x << 1 | 1, v);
	pushup(x);
}
int query(int l, int r, int x)
{
	if(l <= l(x) && r(x) <= r) return val(x);
	pushdown(x);
	int mid = l(x) + r(x) >> 1, res = 0;
	if(l <= mid) res += query(l, r, x << 1);
	if(r > mid) res += query(l, r, x << 1 | 1);
	return res;
}
int check(int v)
{
	build(1, n, 1, v);
	for(int i = 1;i <= m;i ++)
	{
		int l = Q[i].l, r = Q[i].r, op = Q[i].op;
		int sum = query(l, r, 1);
		if(sum == 0) continue;
		update(l, r, 1, 0);
		if(op == 0) update(r - sum + 1, r, 1, 1);
		else update(l, l + sum - 1, 1, 1);
	}
	return query(pos, pos, 1);
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin >> n >> m;
	for(int i = 1;i <= n;i ++) cin >> a[i];
	for(int i = 1;i <= m;i ++) cin >> Q[i].op >> Q[i].l >> Q[i].r;
	cin >> pos;
	int l = 1, r = n, res;
	while(l <= r)
	{
		int mid = l + r >> 1;
		if(check(mid)) l = mid + 1, res = mid;
		else r = mid - 1;
	}
	cout << res << '\n';
    return 0;
}

原文链接:https://www.cnblogs.com/Svemit/p/17300244.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:线段树好题! P2824 [HEOI2016/TJOI2016]排序 题解 - Python技术站

(0)
上一篇 2023年4月17日
下一篇 2023年4月17日

相关文章

  • JavaScript数据结构Number

    JavaScript数据结构Number 简介 JavaScript中的Number是一种表示数字的数据类型,包括整数和浮点数。Number类型的值是不可变的。 数字类型(Number)的创建 数字类型可以通过直接赋值的方式创建,如: let num = 10; // 整数 let floatNum = 3.14; // 浮点数 另外,JavaScript还…

    数据结构 2023年5月17日
    00
  • 详解python算法常用技巧与内置库

    Python是一种高级编程语言,它提供了许多内置库和算法技巧,可以帮助我们更轻松地解决各种问题。在本文中,我们将介绍一些Python算法常用技巧和内置库。 算法常用技巧 1. 双指针技巧 双指针技巧是一种常用的算法技巧,它可以帮助我们在数组或链表中查找元素。双指针技巧通常使用两个指针,一个指针从数组或链表的开头开始,另一个指针从数组或链表的结尾开始,然后两个…

    python 2023年5月13日
    00
  • Java数据结构之图的路径查找算法详解

    Java数据结构之图的路径查找算法详解 什么是图? 在计算机科学中,图是一种非常常见的数据结构,用于表示图形和网络等概念。图由节点和边组成,其中节点表示实体,边表示这些实体之间的关系。节点和边可以表示各种各样的实体和关系,因此图在计算机科学中具有广泛的应用。 图的路径查找算法 路径查找算法是一个用途广泛的算法,它用于查找从一个节点到另一个节点的路径。在图中,…

    数据结构 2023年5月17日
    00
  • C语言实现学生信息管理系统(链表)

    C语言实现学生信息管理系统(链表) 简介 学生信息管理系统是管理学生的一种系统,可以实现添加、查找、删除和修改学生信息等功能。本文将使用C语言实现学生信息管理系统,并通过链表的方式进行实现。 前提条件 在开始之前,我们需要了解如下内容: C语言基础知识 链表的基本概念和使用 系统架构 学生信息管理系统主要包含以下几个模块: 学生信息结构体 添加学生信息 查找…

    数据结构 2023年5月17日
    00
  • 「学习笔记」BSGS

    「学习笔记」BSGS 点击查看目录 目录 「学习笔记」BSGS Baby-step Giant-step 问题 算法 例题 Discrete Logging 代码 P3306 [SDOI2013] 随机数生成器 思路 P2485 [SDOI2011]计算器 思路 Matrix 思路 代码 Baby-step Giant-step 问题 在 \(O(\sqrt…

    算法与数据结构 2023年4月17日
    00
  • Java数据结构之链表详解

    Java数据结构之链表详解 什么是链表? 链表是一种基本的动态数据结构,它的基本思想是利用指针将一些零散的内存块串联起来,形成一个逻辑上的整体。链表由一些称为节点的元素组成,每个节点保存两个部分:数据和指向下一个节点的指针。相比于数组这种静态数据结构,链表具有动态性,我们可以通过动态的增加或删除节点来改变链表的大小。 链表的分类 单向链表:每个节点只有一个指…

    数据结构 2023年5月17日
    00
  • python实现鸢尾花三种聚类算法(K-means,AGNES,DBScan)

    Python实现鸢尾花三种聚类算法(K-means, AGNES, DBScan) 1. 简介 聚类是一种无监督学习算法,它将相似的数据点分组到同一个簇中。本文将介绍如何使用Python实现三种聚类算法:K-means、AGNES和DBScan,并使用鸢尾花数据集进行演示。 2. 数据集 我们将使用鸢尾花数据集来演示如何使用聚类算法。该数据集包含150个样本…

    python 2023年5月14日
    00
  • python数据结构之二叉树的遍历实例

    以下是关于“Python数据结构之二叉树的遍历实例”的完整攻略: 简介 二叉树是一种常见的数据结构,它由节点和边组成,每个节点最多有两个子节点。在本教程中,我们将介绍如何使用Python实现二叉树的遍历,并提供一些示例说明。 二叉树的遍历 二叉树的遍历是指按照一定的顺序访问二叉树中的所有节点。常见的二叉树遍历方式有三种:前序遍历、中序遍历和后序遍历。前序遍历…

    python 2023年5月14日
    00
合作推广
合作推广
分享本页
返回顶部