[BZOJ 3196][模板] 二(遮蔽)平衡樹 - 樹狀陣列套主席樹
阿新 • • 發佈:2018-11-22
主席樹維護每個點的字首權值情況.
樹狀陣列維護區間.
想法比較直觀, 聯賽的教訓是想到了要能快寫.
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; const int maxn = 3e+5 + 5; const int maxp = maxn * 50; struct opt { int typ, a, b, c; }opl[maxn]; int n, m, lp[maxn], rp[maxn]; int id[maxn], s[maxn]; int ls[maxp], rs[maxp], su[maxp], cnt; int val[maxn], cpy[maxn], tot; inline int rd() { register int x = 0, f = 0, c = getchar(); while (!isdigit(c)) { if (c == '-') f = 1; c = getchar(); } while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar(); return f ? -x : x; } inline void init(int l, int r) { for (; l; l -= (l & -l)) lp[l] = id[l]; for (; r; r -= (r & -r)) rp[r] = id[r]; } inline void toLeft(int l, int r) { for (; l; l -= (l & -l)) lp[l] = ls[lp[l]]; for (; r; r -= (r & -r)) rp[r] = ls[rp[r]]; } inline void toRight(int l, int r) { for (; l; l -= (l & -l)) lp[l] = rs[lp[l]]; for (; r; r -= (r & -r)) rp[r] = rs[rp[r]]; } inline int getLeft(int x, int *p) { int ret = 0; for (; x; x -= (x & -x)) ret += su[ls[p[x]]]; return ret; } int update(int lst, int l, int r, int p, int x) { int newrt = ++cnt; ls[newrt] = ls[lst]; rs[newrt] = rs[lst]; su[newrt] = su[lst] + x; if (l == r) return newrt; int mid = (l + r) >> 1; if (p <= mid) ls[newrt] = update(ls[lst], l, mid, p, x); else rs[newrt] = update(rs[lst], mid + 1, r, p, x); return newrt; } int getRank(int l, int r, int L, int R, int x) { if (l == r) return 0; int mid = (l + r) >> 1; if (x <= mid) { toLeft(L, R); return getRank(l, mid, L, R, x); } else { int tmp = getLeft(R, rp) - getLeft(L, lp); toRight(L, R); return getRank(mid + 1, r, L, R, x) + tmp; } } int getKth(int l, int r, int L, int R, int k) { if (l == r) return cpy[l]; int mid = (l + r) >> 1; int tmp = getLeft(R, rp) - getLeft(L, lp); if (k <= tmp) { toLeft(L, R); return getKth(l, mid, L, R, k); } else { toRight(L, R); return getKth(mid + 1, r, L, R, k - tmp); } } inline void add(int p, int x, int v) { for (; p <= n; p += (p & -p)) id[p] = update(id[p], 1, tot, x, v); } int main() { n = rd(); m = rd(); for (int i = 1; i <= n; ++i) val[i] = cpy[i] = rd(); tot = n; for (int i = 1; i <= m; ++i) { opl[i].typ = rd(); if (opl[i].typ == 3) { opl[i].a = rd(); opl[i].b = rd(); cpy[++tot] = opl[i].b; } else { opl[i].a = rd(); opl[i].b = rd(); opl[i].c = rd(); if (opl[i].typ != 2) cpy[++tot] = opl[i].c; } } sort(cpy + 1, cpy + 1 + tot); tot = unique(cpy + 1, cpy + 1 + tot) - (cpy + 1); for (int i = 1; i <= n; ++i) { int x = lower_bound(cpy + 1, cpy + 1 + tot, val[i]) - cpy; add(i, x, 1); } for (int i = 1; i <= m; ++i) { if (opl[i].typ == 3) { int pos = opl[i].a, newval = opl[i].b; int ori = lower_bound(cpy + 1, cpy + 1 + tot, val[pos]) - cpy; int upd = lower_bound(cpy + 1, cpy + 1 + tot, newval) - cpy; add(pos, ori, -1); val[pos] = newval; add(pos, upd, 1); } else { int ql = opl[i].a - 1, qr = opl[i].b, qv; init(ql, qr); if (opl[i].typ != 2) qv = lower_bound(cpy + 1, cpy + 1 + tot, opl[i].c) - cpy; if (opl[i].typ == 1) printf("%d\n", getRank(1, tot, ql, qr, qv) + 1); else if (opl[i].typ == 2) printf("%d\n", getKth(1, tot, ql, qr, opl[i].c)); else if (opl[i].typ == 4) { int k = getRank(1, tot, ql, qr, qv); if (!k) puts("-2147483647"); else { init(ql, qr); printf("%d\n", getKth(1, tot, ql, qr, k)); } } else { int k = getRank(1, tot, ql, qr, qv + 1); if (k > opl[i].b - opl[i].a) puts("2147483647"); else { init(ql, qr); printf("%d\n", getKth(1, tot, ql, qr, k + 1)); } } } } return 0; }
線段樹套平衡樹寫法
等待填坑.