这种含有修改操作的就难以用后缀数组实现了,求LCP这种区间相等的类型可以想到用hash判断,同时LCP的答案大小符合二分条件可以二分求出,如果只有修改可以用线段树维护,因为还有有插入操作所以想到平衡树。
#include<cstdio> const int N = 2e5 + 5; const int base = 237; typedef unsigned long long ull; ull pow[N]; struct Splay{ #define ls p[u].son[0] #define rs p[u].son[1] #define maxn N int root = 1, cnt = 2; struct Node{ int fa, size, len; // size是子树大小,len是除去虚点的子树大小 ull hash, val; int son[2]; }p[maxn]; inline int identify(int u){ return p[p[u].fa].son[1] == u; } inline void update(int u){ p[u].size = p[ls].size + p[rs].size + 1; p[u].len = p[ls].len + p[rs].len + (u > 2); // 判断u > 2是为了除去虚点的影响 p[u].hash = (p[ls].hash * base + p[u].val) * pow[p[rs].len] + p[rs].hash; } void rotate(int u){ int f = p[u].fa, gf = p[f].fa, sta = identify(u), sta_f = identify(f); p[f].son[sta] = p[u].son[sta ^ 1]; p[p[f].son[sta]].fa = f; p[u].son[sta^1] = f, p[f].fa = u, p[u].fa = gf; p[gf].son[sta_f] = u; update(f); } void splay(int u, int goal){ for(int f; (f = p[u].fa) && (f != goal); rotate(u)){ if(p[f].fa != goal) rotate(identify(u) == identify(f) ? f : u); } if(!goal) root = u; update(u); } ull Hash(int u, int len){ int L = find_Kth(u), R = find_Kth(u + len + 1); splay(L, 0), splay(R, L); return p[p[R].son[0]].hash; } int LCQ(int x, int y){ int L = 0, R = cnt - 1 - y, ans; while(L <= R){ int mid = (L + R) >> 1; if(Hash(x, mid) == Hash(y, mid)) L = mid + 1, ans = mid; else R = mid - 1; } return ans; } int find_Kth(int k){ int u = root; while(1){ if(p[ls].size + 1 == k) return u; if(p[ls].size >= k) u = ls; else k -= p[ls].size + 1, u = rs; } } void insert(int u, int val){ int L = find_Kth(u), R = find_Kth(u + 1); splay(L, 0), splay(R, L); p[++cnt].val = val, p[R].son[0] = cnt, p[cnt].fa = R; splay(cnt, 0); } void modify(int x, int val){ int L= find_Kth(x), R = find_Kth(x + 2); splay(L, 0), splay(R, L); p[p[R].son[0]].val = val; update(p[R].son[0]), update(R), update(L); } }Tree; int m, x, y; char s[N], opt[2]; int main(){ scanf("%s%d", s + 1, &m); pow[0] = 1; for(int i = 1; i < N; ++i) pow[i] = pow[i - 1] * base; // 插入两个虚点作为序列的左右端点,方便插入、查找等操作 Tree.p[1].son[1] = 2, Tree.p[2].fa = 1; Tree.update(1), Tree.update(2); for(int i = 1; s[i]; ++i) Tree.insert(i, s[i]); while(m--){ scanf("%s", opt); if(opt[0] == 'Q'){ scanf("%d%d", &x, &y); if(x > y) x ^= y ^= x ^= y; printf("%d ", Tree.LCQ(x, y)); } else if(opt[0] == 'R'){ scanf("%d%s", &x, opt); Tree.modify(x, opt[0]); } else{ scanf("%d%s", &x, opt); Tree.insert(x + 1, opt[0]); } } return 0; }