[HEOI2016/TJOI2016]排序
阿新 • • 發佈:2021-07-21
\(\text{Solution}\)
非常巧妙的二分答案
因為只有一個詢問,且答案滿足單調性,所以二分答案 \(mid\)
原序列中大於等於 \(mid\) 的數的位置賦為 \(1\),否則賦為 \(0\)
然後走一遍排序操作,用線段樹賦值完成排序
最後檢查 \(q\) 位置上的情況,\(0\) 就不行,\(1\) 就可以
\(mid\) 越小越容易,越大越困難,臨界點即為答案
\(\text{Code}\)
#include <cstdio> #include <cstring> #define ls (p << 1) #define rs (ls | 1) #define re register using namespace std; const int N = 1e5 + 5; int n, m, q, a[N]; struct node{int op, l, r;}b[N]; inline void read(int &x) { x = 0; char ch = getchar(); while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); } int tag[N << 2], sum[N << 2]; inline void pushup(int p){sum[p] = sum[ls] + sum[rs];} inline void pushdown(int p, int l, int r) { if (tag[p] == -1) return; int mid = (l + r) >> 1; if (!tag[p]) sum[ls] = mid - l + 1, sum[rs] = r - mid; else sum[ls] = sum[rs] = 0; tag[ls] = tag[rs] = tag[p], tag[p] = -1; } void update(int p, int l, int r, int x, int y, int v) { if (x > r || y < l) return; if (x <= l && r <= y) { tag[p] = v, sum[p] = (v ? 0 : r - l + 1); return; } pushdown(p, l, r); int mid = (l + r) >> 1; if (x <= mid) update(ls, l, mid, x, y, v); if (y > mid) update(rs, mid + 1, r, x, y, v); pushup(p); } int query_0(int p, int l, int r, int x, int y) { if (x > r || y < l) return 0; if (x <= l && r <= y) return sum[p]; pushdown(p, l, r); int mid = (l + r) >> 1, res = 0; if (x <= mid) res = query_0(ls, l, mid, x, y); if (y > mid) res += query_0(rs, mid + 1, r, x, y); return res; } inline int check(int mid) { memset(tag, 255, sizeof tag), memset(sum, 0, sizeof sum); for(re int i = 1; i <= n; i++) update(1, 1, n, i, i, a[i] >= mid); for(re int i = 1, l, r, num; i <= m; i++) { num = query_0(1, 1, n, b[i].l, b[i].r); if (!b[i].op) l = b[i].l, r = b[i].l + num - 1, update(1, 1, n, l, r, 0), update(1, 1, n, r + 1, b[i].r, 1); else l = b[i].l, r = b[i].l + (b[i].r - b[i].l + 1 - num) - 1, update(1, 1, n, l, r, 1), update(1, 1, n, r + 1, b[i].r, 0); } return !query_0(1, 1, n, q, q); } int main() { read(n), read(m); for(re int i = 1; i <= n; i++) read(a[i]); int l = 1, r = n, mid, ans = 0; for(re int i = 1; i <= m; i++) read(b[i].op), read(b[i].l), read(b[i].r); read(q); while (l <= r) { mid = (l + r) >> 1; if (check(mid)) ans = mid, l = mid + 1; else r = mid - 1; } printf("%d\n", ans); }