首页 > 其他分享 >P2824 [HEOI2016/TJOI2016]排序 题解

P2824 [HEOI2016/TJOI2016]排序 题解

时间:2023-04-09 14:01:38浏览次数:57  
标签:res int 题解 tr mid TJOI2016 P2824 排序 define

题目传送门

前言

线段树好题!!!!
咕咕了挺久的一道题目,很早之前就想写了,今天终于找了个时间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;
}

标签:res,int,题解,tr,mid,TJOI2016,P2824,排序,define
From: https://www.cnblogs.com/Svemit/p/17300244.html

相关文章

  • Windows10锁屏1分钟息屏问题解决 - 桌面、锁屏、屏保一站搞定
    Windows10桌面、锁屏、屏保一站解决一、背景在Windows10以前的Windows中,桌面和锁屏界面的超时息屏时间是一致的,都是简单在控制面板的电源设置中,调整关闭显示器时间即可。但到了Windows10这个世代,电源中的关闭显示器时间,只对桌面有效,也就是对没有锁屏的Windows桌面有效;一旦用户......
  • 2023年4月蓝桥杯B组A到G题解析
    试题A:阶乘求和本题总分:5分【问题描述】令S=1!+2!+3!+...+202320232023!,求S的末尾9位数字。提示:答案首位不为0。【答案提交】这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得......
  • Vs-Code—控制台+乱码问题解决
    在创建第一个项目之前,需要按照环境和插件,这里对此不做阐述,读者自行查找资料。解决问题:更改输出位置+c/cpp中文乱码1、集成控制台输出->外部控制台输出1.1、c/cpp文件1、新建文件2、编写一段代码2、在运行和调试按钮下,点击创建launch.json文件在launch.json文件中,改"externalConsole......
  • Mondriaan's Dream 【POJ2411】 题解
    Mondriaan'sDream【POJ2411】题解——ByZy注:原题中的\(h,w\)在本文中使用\(n,m\)代替。一.题意分析:题目要求给定一个一定大小的矩形棋盘,求出使用\(1\times2\)大小的木条填充一共有多少种方案。读题,发现数据范围\((1\leh,w\le11)\),考虑使用状压DP算法,于是......
  • ECE 5101/CSE 5463 问题解答
    ECE5101/CSE5463,Spring2023Due:Apr.811:59pm,2023onCarmenHomeworkAssignment#4LateSubmissionNOTAcceptedHomeworkAssignment#41.(20points)InanunslottedALOHAsystem,thepacketarrivaltimesofallusersformaPoissonprocesshavingarate......
  • ARC130D ZigZag Tree 题解
    题目链接考虑这棵树在满足条件下是什么样子的?我们发现如果对于一棵树黑白染色,白色表示周围的点大于自身,黑色的点反之,是满足条件的。同时,将黑白点反色也是满足条件的。我们考虑进行\(\text{dp}\),设\(dp_{i,j,0/1}\)表示以点\(i\)为根的子树,\(i\)点权值的排名是\(j\),且......
  • 【牛客小白月赛70】A-F题解【小d和超级泡泡堂】【小d和孤独的区间】【小d的博弈】【小
    比赛传送门:https://ac.nowcoder.com/acm/contest/53366难度适中。......
  • Edu Round 板刷计划 4. Educational Codeforces Round 4 题解
    ChangeLog:2023.04.06开坑.A-TheTextSplitting弱智题.枚举分出来多少个长度为\(p\)的串,则能计算出长度为\(q\)的串有多少个,若合法则直接输出即可.无解输出-1.Samplesubmission.B-HDDisOutdatedTechnology比A还弱智.直接记录每个数的位置,然后模拟一......
  • [ARC127D] Sum of Min of Xor 题解
    先把\(i\)对\(j\)的约束去掉。没有\(\min\)的情况是trival的,发现瓶颈在于如何比较两个数之间的大小。可以发现,对两个二进制数,我们本质上是想要找到它们第一个不同的位置。于是考虑从最高位开始,将\((a_i,b_i)\)按最高位分组为\((0,0),(0,1),(1,0),(1,1)\)四组。每组内......
  • 【题解】P4898 [IOI2018] seats 排座位
    思路线段树。题意可以转化成每次判定有多少个前缀满足所有结点构成矩形。首先排除确定矩阵坐标再数答案的做法,因为太难。所以考虑如何对前缀进行判定。一个简单的想法是维护前\(i\)个点中\(x,y\)坐标的最值,但这样只能暴力看矩阵中的所有元素,跑得很慢。不妨思考一下合法......