BZOJ3682: Phorni(字尾平衡樹)
阿新 • • 發佈:2019-01-12
傳送門
字尾平衡樹模板題
用平衡樹維護每一個字尾的排名
關鍵在於查詢兩個字尾的大小
可以用二分加hash,複雜度 \(log^2n\) 插入
或者:
每次前面插入一個字元,先比較兩個字尾第一個字元的大小
而後面的大小我們已經在平衡樹上維護好了
像這樣分配權值
給樹上每個子樹一個實數權值區間 \([l,r]\),這個點權值為 \(mid=\frac{l+r}{2}\)
左子樹 \([l,mid]\) 右子樹 \([mid,r]\)
那麼可以做到 \(O(1)\) 比較
只需要選擇一個樹高 \(log\) 的樹(treap/替罪羊樹)使得滿足精度要求即可
最後用線段樹維護一下每個幻影的最小的字尾
# include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn(1e6 + 5); const double alpha(0.75); int ls[maxn], rs[maxn], rt, tot, size[maxn], que[maxn], cnt; double val[maxn]; int mn[maxn << 1], id[maxn], n, m, p[maxn], pos[maxn]; char s[maxn]; void Dfs(int u) { if (!u) return; Dfs(ls[u]), que[++cnt] = u, Dfs(rs[u]); } int Build(int l, int r, double vl, double vr) { if (l > r) return 0; double midv; int mid, o; mid = (l + r) >> 1, o = que[mid], midv = (vl + vr) * 0.5; ls[o] = rs[o] = 0, val[o] = midv; ls[o] = Build(l, mid - 1, vl, midv); rs[o] = Build(mid + 1, r, midv, vr); size[o] = size[ls[o]] + size[rs[o]] + 1; return o; } int Rebuild(int x, double vl, double vr) { cnt = 0, Dfs(x); return Build(1, cnt, vl, vr); } inline int Compare(int x, int y) { return (s[x] ^ s[y]) ? s[x] < s[y] : val[id[x - 1]] < val[id[y - 1]]; } int Insert(int &x, double vl, double vr, int ps) { double midv; int ret; midv = (vl + vr) * 0.5; if (!x) { x = ++tot, val[x] = midv, pos[x] = ps, size[x] = 1; return x; } if (alpha * size[x] < max(size[ls[x]], size[rs[x]])) x = Rebuild(x, vl, vr); if (Compare(ps, pos[x])) ret = Insert(ls[x], vl, midv, ps); else ret = Insert(rs[x], midv, vr, ps); size[x] = size[ls[x]] + size[rs[x]] + 1; return ret; } void Modify(int x, int l, int r, int ps) { int mid; if (l == r) mn[x] = l; else { mid = (l + r) >> 1; ps <= mid ? Modify(x << 1, l, mid, ps) : Modify(x << 1 | 1, mid + 1, r, ps); mn[x] = val[id[p[mn[x << 1]]]] <= val[id[p[mn[x << 1 | 1]]]] ? mn[x << 1] : mn[x << 1 | 1]; } } int Query(int x, int l, int r, int ql, int qr) { int mid, ret, v; if (ql <= l && qr >= r) return mn[x]; mid = (l + r) >> 1, ret = -1, v; if (ql <= mid) ret = Query(x << 1, l, mid, ql, qr); if (qr > mid) { v = Query(x << 1 | 1, mid + 1, r, ql, qr); ret = (ret == -1 || val[id[p[v]]] < val[id[p[ret]]]) ? v : ret; } return ret; } int main() { int i, l, r, k, ans, type, len; char op; scanf("%d%d%d%d %s", &n, &m, &len, &type, s + 1); reverse(s + 1, s + len + 1), val[0] = -1; for (i = 1; i <= len; ++i) id[i] = Insert(rt, 0, 1, i); for (i = 1; i <= n; ++i) scanf("%d", &p[i]), Modify(1, 1, n, i); ans = 0; for (i = 1; i <= m; ++i) { scanf(" %c", &op); if (op == 'I') { scanf(" %d", &k); if (type) k = (k ^ ans); s[++len] = k + 'a'; id[len] = Insert(rt, 0, 1, len); } else if (op == 'C') { scanf("%d%d", &l, &r); p[l] = r, Modify(1, 1, n, l); } else scanf("%d%d", &l, &r), printf("%d\n", ans = Query(1, 1, n, l, r)); } return 0; }