BZOJ 4552 [Tjoi2016&Heoi2016]排序

4552: [Tjoi2016&Heoi2016]排序

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 2035  Solved: 1015
[Submit][Status][Discuss]

Description

在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题
,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排
序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q
位置上的数字。

Input

输入数据的第一行为两个整数n和m。n表示序列的长度,m表示局部排序的次数。1 <= n, m <= 10^5第二行为n个整
数,表示1到n的一个全排列。接下来输入m行,每一行有三个整数op, l, r, op为0代表升序排序,op为1代表降序
排序, l, r 表示排序的区间。最后输入一个整数q,q表示排序完之后询问的位置, 1 <= q <= n。1 <= n <= 10^5
,1 <= m <= 10^5
 

Output

 输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。

Sample Input

6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3

Sample Output

5
总结:
考虑二分答案,将问题转化为判定性问题
可以发现,我们不好直接排序,但是如果是01串,就可以用线段树维护排序
询问只有一组q,于是二分最后的答案(mid)
将原数组中大于mid的设为0,小于等于mid的设为1,建立线段树
然后每次排序,相当于对01串进行排序
最后查询q位置的数,如果为1,则ans = mid, r = mid - 1否则l = mid + 1
#include <bits/stdc++.h>
using namespace std;

const int maxn = 4e5 + 7;
int sum[maxn], tag[maxn], a[maxn], n;
struct Node {
	int op, l, r;
} q[maxn]; int Q, m;

void update(int o) {
	sum[o] = sum[o << 1] + sum[o << 1 | 1];
}
void pushdown(int o, int l, int r) {
	if(tag[o] != -1) {
		int mid = (l + r) >> 1;
		tag[o << 1] = tag[o]; tag[o << 1 | 1] = tag[o];
		sum[o << 1] = tag[o] * (mid - l + 1);
		sum[o << 1 | 1] = tag[o] * (r - mid); tag[o] = -1; 
	}
}
int Query(int o, int l, int r, int ql, int qr) {
	if(ql <= l && r <= qr) return sum[o];
	int mid = (l + r) >> 1; pushdown(o, l, r);
	int res = 0;
	if(ql <= mid) res += Query(o << 1, l, mid, ql, qr);
	if(qr > mid) res += Query(o << 1 | 1, mid + 1, r, ql, qr);
	return res;
}
void Modify(int o, int l, int r, int ql, int qr, int z) {
	if(ql <= l && r <= qr) {
		sum[o] = z * (r - l + 1); tag[o] = z; return;
	} int mid = (l + r) >> 1; pushdown(o, l, r);
	if(ql <= mid) Modify(o << 1, l, mid, ql, qr, z);
	if(qr > mid) Modify(o << 1 | 1, mid + 1, r, ql, qr, z);
	update(o);
}
void Build(int o, int l, int r, int x) {
	tag[o] = -1;
	if(l == r) {
		sum[o] = (a[l] <= x); return;
	} int mid = (l + r) >> 1;
	Build(o << 1, l, mid, x); Build(o << 1 | 1, mid + 1, r, x);
	update(o);
}
bool check(int x) {
	Build(1, 1, n, x);
	for (int i = 1; i <= m; ++i) {
		int res = Query(1, 1, n, q[i].l, q[i].r);
		if(res == 0 || res == (q[i].r - q[i].l + 1)) continue;
		if(!q[i].op) {
			Modify(1, 1, n, q[i].l, q[i].l + res - 1, 1);
			Modify(1, 1, n, q[i].l + res, q[i].r, 0);
		} else {
			Modify(1, 1, n, q[i].r - res + 1, q[i].r, 1);
			Modify(1, 1, n, q[i].l, q[i].r - res, 0);
		}
	} return Query(1, 1, n, Q, Q);
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
	for (int i = 1; i <= m; ++i) scanf("%d%d%d", &q[i].op, &q[i].l, &q[i].r);
	int l = 1, r = n, ans = 0; scanf("%d", &Q);
    while(l <= r) {
    	int mid = (l + r) >> 1;
    	if(check(mid)) {
    		ans = mid; r = mid - 1;
		} else l = mid + 1;
    } printf("%d\n", ans);
	return 0;
}

  

 

猜你喜欢

转载自www.cnblogs.com/oi-forever/p/9190594.html