【题目链接】
【思路要点】
- 替罪羊树套权值线段树。
- 时间复杂度\(O(NLog^2N)\)。
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXN 70005 #define MAXV 70005 #define MAXP 20000005 #define ALPHA 0.68 template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } void getopt(char &c) { c = getchar(); while (c != 'Q' && c != 'I' && c != 'M') c = getchar(); } struct Segment_Tree { int now, root[MAXN]; int top, mem[MAXP]; int lc[MAXP], rc[MAXP], sum[MAXP]; void init(int n) { for (int i = 1; i <= n; i++) mem[i] = n - i + 1; top = n; } int new_node() { int tmp = mem[top--]; lc[tmp] = rc[tmp] = 0; sum[tmp] = 0; return tmp; } void recycle(int x) { mem[++top] = x; } void dfs(int x) { if (lc[x]) dfs(lc[x]); if (rc[x]) dfs(rc[x]); recycle(x); } void clear(int x) { if (root[x]) dfs(root[x]); root[x] = 0; } void modify(int &root, int l, int r, int pos, int delta) { if (root == 0) root = new_node(); sum[root] += delta; if (l == r) return; int mid = (l + r) / 2; if (mid >= pos) modify(lc[root], l, mid, pos, delta); else modify(rc[root], mid + 1, r, pos, delta); } void modify(int x, int v, int d) { modify(root[x], 0, MAXV, v, d); } int query(int k, int len, int *type, int *home) { int l = 0, r = MAXV; for (int i = 1; i <= len; i++) home[i] = root[home[i]]; while (l < r) { int mid = (l + r) / 2; int tsum = 0; for (int i = 1; i <= len; i++) tsum += type[i] * sum[lc[home[i]]]; if (tsum >= k) { r = mid; for (int i = 1; i <= len; i++) home[i] = lc[home[i]]; } else { l = mid + 1; k -= tsum; for (int i = 1; i <= len; i++) home[i] = rc[home[i]]; } } return l; } } SMT; struct Scapegoat_Tree { int root, reroot; int len, tindex[MAXN]; int type[MAXN], home[MAXN]; int top, mem[MAXN]; int lc[MAXN], rc[MAXN]; int index[MAXN], size[MAXN]; void init(int n) { for (int i = 1; i <= n; i++) mem[i] = n - i + 1; top = n; } int new_node() { int tmp = mem[top--]; lc[tmp] = rc[tmp] = 0; index[tmp] = 0; size[tmp] = 0; SMT.clear(tmp); return tmp; } void recycle(int x) { mem[++top] = x; } void update(int x) { size[x] = 1; size[x] += size[lc[x]]; size[x] += size[rc[x]]; } void dfs(int root) { if (root != reroot) recycle(root); if (lc[root]) dfs(lc[root]); tindex[++len] = index[root]; if (rc[root]) dfs(rc[root]); } void rebuild(int root, int l, int r) { for (int i = l; i <= r; i++) SMT.modify(root, tindex[i], 1); int mid = (l + r) / 2; index[root] = tindex[mid]; if (mid > l) { lc[root] = new_node(); rebuild(lc[root], l, mid - 1); } if (mid < r) { rc[root] = new_node(); rebuild(rc[root], mid + 1, r); } update(root); } void rebuild(int root) { len = 0; dfs(root); lc[root] = rc[root] = 0; index[root] = size[root] = 0; SMT.clear(root); rebuild(root, 1, len); } void index_init(int n, int *a) { for (int i = 1; i <= n; i++) tindex[i] = a[i]; root = new_node(); rebuild(root, 1, n); } bool unbalance(int root) { return max(size[lc[root]], size[rc[root]]) > size[root] * ALPHA + 1; } void insert(int &root, int pos, int value) { if (root == 0) { root = new_node(); index[root] = value; size[root] = 1; SMT.modify(root, value, 1); return; } SMT.modify(root, value, 1); size[root]++; if (pos <= size[lc[root]] + 1) insert(lc[root], pos, value); else insert(rc[root], pos - size[lc[root]] - 1, value); if (unbalance(root)) reroot = root; } void insert(int pos, int value) { reroot = 0; insert(root, pos, value); if (reroot) rebuild(reroot); } int modify(int root, int pos, int value) { /*Return Value: Old Index*/ SMT.modify(root, value, 1); if (pos <= size[lc[root]]) { int tmp = modify(lc[root], pos, value); SMT.modify(root, tmp, -1); return tmp; } else { pos -= size[lc[root]]; if (pos == 1) { int tmp = index[root]; index[root] = value; SMT.modify(root, tmp, -1); return tmp; } int tmp = modify(rc[root], pos - 1, value); SMT.modify(root, tmp, -1); return tmp; } } void modify(int pos, int value) { modify(root, pos, value); } void getquery(int root, int l, int r, int t) { int mid = size[lc[root]] + 1; if (mid > r) getquery(lc[root], l, r, t); else if (mid < l) getquery(rc[root], l - mid, r - mid, t); else { len++; home[len] = root; type[len] = t; if (l != 1) getquery(lc[root], 1, l - 1, -t); if (r != size[root]) getquery(rc[root], r - size[lc[root]], size[root] - size[lc[root]] - 1, -t); } } int query(int l, int r, int k) { len = 0; getquery(root, l, r, 1); return SMT.query(k, len, type, home); } } SGT; int num[MAXN]; int main() { SMT.init(MAXP - 1); SGT.init(MAXN - 1); int lastans = 0; int n; read(n); for (int i = 1; i <= n; i++) read(num[i]); SGT.index_init(n, num); int m; read(m); for (int i = 1; i <= m; i++) { char opt; int l, r, v; getopt(opt); if (opt == 'I') { read(l), read(v); l ^= lastans; v ^= lastans; SGT.insert(l, v); } if (opt == 'Q') { read(l), read(r), read(v); l ^= lastans; r ^= lastans; v ^= lastans; printf("%d\n", lastans = SGT.query(l, r, v)); } if (opt == 'M') { read(l), read(v); l ^= lastans; v ^= lastans; SGT.modify(l, v); } } return 0; }