4552: [Tjoi2016&Heoi2016]排序
Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 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
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; }