Bzoj 1014&Luogu 4036 火星人Prefix(FHQ-Treap)
阿新 • • 發佈:2018-12-22
題面
題解
首先,這種帶修改的是不能用$SA$的,然後,我們做$SA$的題一般也能二分+$Hash$,所以不妨考慮用$FHQ-Treap$維護樹,然後查詢就用二分+$Hash$。
$Hash$怎麼寫?
$ hash[o]=hash[lc[o]]\times base[siz[rc[o]]+1]+val[o]\times base[siz[rc[o]]]+hash[rc[o]] $
為什麼可以這麼寫呢?想一想,為什麼
我們一般怎麼求一顆維護序列的平衡樹的原序列呢?—中序遍歷
所以嘛,一棵子樹的雜湊值可以轉化成它左子樹的雜湊值+本身的值+右子樹雜湊值
由於怕重複,所以可以考慮將前面兩個值隨便乘上一點什麼東西(比如左子樹或者右子樹的$size$之類的)
#include <ctime> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> template<typename T> void read(T &x) { int flag = 1; x = 0; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); } while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag; } const int N = 3e5 + 10; char s[N]; int m, len, base[N]; int rt, tot, lc[N], rc[N], pri[N], siz[N], h[N], val[N]; inline void upt(int o) { siz[o] = siz[lc[o]] + siz[rc[o]] + 1; h[o] = h[lc[o]] * base[siz[rc[o]] + 1] + val[o] * base[siz[rc[o]]] + h[rc[o]]; } inline int node(int x) { siz[++tot] = 1, val[tot] = h[tot] = x, pri[tot] = rand(); return tot; } void split(int o, int k, int &l, int &r) { if(!o) { l = r = 0; return ; } if(siz[lc[o]] < k) l = o, split(rc[o], k - siz[lc[o]] - 1, rc[o], r); else r = o, split(lc[o], k, l, lc[o]); upt(o); } int merge(int l, int r) { if(!l || !r) return l + r; if(pri[l] < pri[r]) { rc[l] = merge(rc[l], r), upt(l); return l; } else { lc[r] = merge(l, lc[r]), upt(r); return r; } } inline int query(int l, int r) { int x, y, k, ret; split(rt, r, x, y), split(x, l - 1, x, k); ret = h[k], rt = merge(merge(x, k), y); return ret; } int main () { scanf("%s", s + 1), len = strlen(s + 1), srand(19260817), base[0] = 1; for(int i = 1; i < N; ++i) base[i] = base[i - 1] * 27; for(int i = 1; i <= len; ++i) rt = merge(rt, node(s[i] - 'a' + 1)); read(m); char opt[5], ch[5]; int x, y, l, r, k; while(m--) { scanf("%s", opt), read(x); if(opt[0] == 'Q') { read(y); int L = 0, R = std::min(len - x, len - y) + 1, ret; while(L <= R) { int mid = (L + R) >> 1; if(query(x, x + mid - 1) == query(y, y + mid - 1)) ret = mid, L = mid + 1; else R = mid - 1; } printf("%d\n", ret); } else { scanf("%s", ch), split(rt, x, l, r), ++len; if(opt[0] == 'R') --len, split(l, x - 1, l, k); rt = merge(merge(l, node(ch[0] - 'a' + 1)), r); } } return 0; }