洛谷 P2824 [HEOI2016/TJOI2016]排序

传送门

题意

给出一个 $1$ 到 $n$ 的全排列,现在对这个全排列序列进行 $m$ 次局部排序,排序分为两种:$(0,l,r)$ 表示将区间 $[l,r]$ 的数字升序排序,$(1,l,r)$ 表示将区间 $[l,r]$ 的数字降序排序。

最后询问第 $q$ 位置上的数字。$n,m\leq 30000$ 。

题解

你可以看到,最后我们只询问一个固定位置上的数字。

我们来考虑二分这个数字的值 $x$ ,然后建一颗线段树,我们在开始的时候把所有 $\geq x$ 的数字标为 $1$ ,其他数字标为 $0$ 。

然后,我们就可以用线段树区间修改、区间查询和的方法对一段区间排序了。最后我们查询 $q$ 位置,如果结果为 $1$ ,说明 $q$ 上的数组 $\geq x$。

时间复杂度:$\mathcal O\left(m\mathrm{lg}^2 n\right)$

上代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 struct SegmentTree{
 5     #define segc int M = (l + r) >> 1, lc = p << 1, rc = lc | 1
 6     bool one[400005], zero[400005]; int sum[400005], n;
 7     void _down(int p, int l, int r) {
 8         segc; if (one[p]) {
 9             sum[lc] = M-l+1, sum[rc] = r-M;
10             zero[lc] = zero[rc] = 0; one[lc] = one[rc] = 1;
11         }
12         if (zero[p]) {
13             sum[lc] = sum[rc] = 0;
14             zero[lc] = zero[rc] = 1; one[lc] = one[rc] = 0;
15         }
16         one[p] = zero[p] = false;
17     }
18     void _set(int p, int l, int r, int x, int y, int val) {
19         if (l == x && r == y) {
20             if (val) one[p] = 1, zero[p] = 0;
21             else one[p] = 0, zero[p] = 1;
22             sum[p] = val ? (r-l+1) : 0;
23             return;
24         }
25         segc; _down(p, l, r);
26         if (y <= M) _set(lc, l, M, x, y, val);
27         else if (x > M) _set(rc, M+1, r, x, y, val);
28         else _set(lc, l, M, x, M, val), _set(rc, M+1, r, M+1, y, val);
29         sum[p] = sum[lc] + sum[rc];
30     }
31     int _query(int p, int l, int r, int x, int y) {
32         if (l == x && r == y) return sum[p];
33         segc; _down(p, l, r);
34         if (y <= M) return _query(lc, l, M, x, y);
35         else if (x > M) return _query(rc, M+1, r, x, y);
36         else return _query(lc, l, M, x, M) + _query(rc, M+1, r, M+1, y);
37     }
38     inline void init(int N) {
39         n = N;
40         memset(one, 0, sizeof(one)); memset(zero, 0, sizeof(zero));
41         memset(sum, 0, sizeof(sum));
42     }
43     inline void set(int l, int r, int v) { l <= r ? _set(1, 1, n, l, r, v) : void(0); }
44     inline int query(int l, int r) { return _query(1, 1, n, l, r); }
45 } ST;
46 
47 int n, m, Q, a[100005], L[100005], R[100005], op[100005];
48 
49 bool check(int x) {
50     ST.init(n);
51     for (int i=1; i<=n; i++) ST.set(i, i, a[i] >= x);
52     for (int i=1; i<=m; i++) {
53         int ss = ST.query(L[i], R[i]);
54         if (op[i]) {
55             ST.set(L[i], L[i]+ss-1, 1); ST.set(L[i]+ss, R[i], 0);
56         } else {
57             ST.set(R[i]-ss+1, R[i], 1); ST.set(L[i], R[i]-ss, 0);
58         }
59     }
60     return ST.query(Q, Q);
61 }
62 
63 int main() {
64     ios :: sync_with_stdio(false);
65     cin >> n >> m;
66     for (int i=1; i<=n; i++) {
67         cin >> a[i];
68     }
69     for (int i=1; i<=m; i++) {
70         cin >> op[i] >> L[i] >> R[i];
71     }
72     cin >> Q;
73     int l = 1, r = n, ans;
74     while (l <= r) {
75         int mid = (l + r) >> 1;
76         if (check(mid)) l = mid + 1, ans = mid;
77         else r = mid - 1;
78     }
79     cout << ans << endl;
80     return 0;
81 }

猜你喜欢

转载自www.cnblogs.com/mchmch/p/luogu-p2824.html