【题目链接】
【思路要点】
- 替罪羊树套权值线段树。
- 时间复杂度\(O(NLog^2N)\)。
- 由于常数较大,笔者的代码无法在BZOJ上通过。
【代码】
/*TLE of Large Constant*/ #include<bits/stdc++.h> using namespace std; #define MAXN 400005 #define MAXV 1048576 #define MAXLOG 20 #define MAXP 30000005 #define ALPHA 0.78 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 != 'I' && c != 'D' && c != 'C' && c != 'F') 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 depth, int value, int delta) { if (root == 0) root = new_node(); sum[root] += delta; if (depth == 0) return; int bit = 1 << (depth - 1); if (bit & value) modify(rc[root], depth - 1, value ^ bit, delta); else modify(lc[root], depth - 1, value, delta); } void modify(int x, int v, int d) { modify(root[x], MAXLOG, v, d); } int query(int value, int len, int *home) { for (int i = 1; i <= len; i++) home[i] = root[home[i]]; for (int depth = MAXLOG, bit = 1 << (MAXLOG - 1); depth > 0; depth--, bit >>= 1) { if (value & bit) { int tsum = 0; for (int i = 1; i <= len; i++) tsum += sum[lc[home[i]]]; if (tsum >= 1) { for (int i = 1; i <= len; i++) home[i] = lc[home[i]]; } else { value ^= bit; for (int i = 1; i <= len; i++) home[i] = rc[home[i]]; } } else { int tsum = 0; for (int i = 1; i <= len; i++) tsum += sum[rc[home[i]]]; if (tsum >= 1) { value ^= bit; for (int i = 1; i <= len; i++) home[i] = rc[home[i]]; } else { for (int i = 1; i <= len; i++) home[i] = lc[home[i]]; } } } return value; } } SMT; struct Scapegoat_Tree { int root, reroot; int len, tindex[MAXN]; int tMax, tNax, home[MAXN]; int top, mem[MAXN]; int lc[MAXN], rc[MAXN]; int index[MAXN], size[MAXN], rsize[MAXN]; int Max[MAXN], Nax[MAXN]; void init(int n) { for (int i = 1; i <= n; i++) mem[i] = n - i + 1; top = n; Max[0] = Nax[0] = index[0] = -1; } int new_node() { int tmp = mem[top--]; lc[tmp] = rc[tmp] = 0; index[tmp] = -1; size[tmp] = 0; rsize[tmp] = 0; SMT.clear(tmp); return tmp; } void recycle(int x) { SMT.clear(x); mem[++top] = x; } void update(int x) { if (index[x] != -1) size[x] = 1; else size[x] = 0; size[x] += size[lc[x]]; size[x] += size[rc[x]]; rsize[x] = 1; rsize[x] += rsize[lc[x]]; rsize[x] += rsize[rc[x]]; Max[x] = index[x]; Nax[x] = -1; int tmp; tmp = Max[lc[x]]; if (tmp > Max[x]) Nax[x] = Max[x], Max[x] = tmp; else Nax[x] = max(Nax[x], tmp); tmp = Max[rc[x]]; if (tmp > Max[x]) Nax[x] = Max[x], Max[x] = tmp; else Nax[x] = max(Nax[x], tmp); tmp = Nax[lc[x]]; if (tmp > Max[x]) Nax[x] = Max[x], Max[x] = tmp; else Nax[x] = max(Nax[x], tmp); tmp = Nax[rc[x]]; if (tmp > Max[x]) Nax[x] = Max[x], Max[x] = tmp; else Nax[x] = max(Nax[x], tmp); } void dfs(int root) { if (root != reroot) recycle(root); if (lc[root]) dfs(lc[root]); if (index[root] != -1) 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); if (l == r) { index[root] = tindex[l]; update(root); return; } int mid = (l + r) / 2; index[root] = -1; lc[root] = new_node(); rebuild(lc[root], l, mid); 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(rsize[lc[root]], rsize[rc[root]]) > rsize[root] * ALPHA + 1; } int cnt(int root) {return index[root] != -1; } void insert(int &root, int pos, int value) { if (cnt(root)) { int tmp = root, tnp = new_node(); index[tnp] = Max[tnp] = value; Nax[tnp] = -1; size[tnp] = rsize[tnp] = 1; SMT.modify(tnp, value, 1); root = new_node(); if (pos == 0) swap(tmp, tnp); lc[root] = tmp, rc[root] = tnp; SMT.modify(root, index[tmp], 1); SMT.modify(root, index[tnp], 1); update(root); return; } if (root == 0) { root = new_node(); index[root] = Max[root] = value; Nax[root] = -1; size[root] = rsize[root] = 1; SMT.modify(root, value, 1); return; } SMT.modify(root, value, 1); if (pos <= size[lc[root]]) insert(lc[root], pos, value); else insert(rc[root], pos - size[lc[root]], value); update(root); 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 (cnt(root)) { int tmp = index[root]; index[root] = value; update(root); SMT.modify(root, tmp, -1); return tmp; } if (pos <= size[lc[root]]) { int tmp = modify(lc[root], pos, value); SMT.modify(root, tmp, -1); update(root); return tmp; } else { pos -= size[lc[root]]; int tmp = modify(rc[root], pos, value); SMT.modify(root, tmp, -1); update(root); return tmp; } } void modify(int pos, int value) { modify(root, pos, value); } int del(int &root, int pos) { /*Return Value: Old Index*/ if (cnt(root)) { int tmp = index[root]; recycle(root); root = 0; return tmp; } if (pos <= size[lc[root]]) { int tmp = del(lc[root], pos); SMT.modify(root, tmp, -1); update(root); return tmp; } else { pos -= size[lc[root]]; int tmp = del(rc[root], pos); SMT.modify(root, tmp, -1); update(root); return tmp; } } void del(int pos) { del(root, pos); } void getquery(int root, int l, int r) { if (l == 1 && r == size[root]) { home[++len] = root; int tmp; tmp = Max[root]; if (tmp > tMax) tNax = tMax, tMax = tmp; else tNax = max(tNax, tmp); tmp = Nax[root]; if (tmp > tMax) tNax = tMax, tMax = tmp; else tNax = max(tNax, tmp); return; } int mid = size[lc[root]]; if (mid >= l) getquery(lc[root], l, min(r, mid)); if (mid + 1 <= r) getquery(rc[root], max(mid + 1, l) - mid, r - mid); } int query(int l, int r) { len = 0; tMax = tNax = -1; getquery(root, l, r); return SMT.query(tNax, len, home); } } SGT; int num[MAXN]; int main() { SMT.init(MAXP - 1); SGT.init(MAXN - 1); int lastans = 0; int n; read(n); int m; read(m); for (int i = 1; i <= n; i++) read(num[i]); SGT.index_init(n, num); for (int i = 1; i <= m; i++) { char opt; int l, r; getopt(opt); if (opt == 'I') { read(l), read(r); l = (l + lastans) % n; r = (r + lastans) % MAXV; SGT.insert(l, r); n++; } if (opt == 'D') { read(l); l = (l + lastans) % n; SGT.del(l + 1); n--; } if (opt == 'C') { read(l), read(r); l = (l + lastans) % n; r = (r + lastans) % MAXV; SGT.modify(l + 1, r); } if (opt == 'F') { read(l), read(r); l = (l + lastans) % n; r = (r + lastans) % n; printf("%d\n", lastans = SGT.query(l + 1, r + 1)); } } return 0; }