1. 程式人生 > >2555: SubString

2555: SubString

maker make mat turn return spa ota isdigit top

2555: SubString

鏈接

題意:

  動態在末尾加入一個字符串,詢問一個字符串出現了多少次。

分析:

  如果沒有動態加入,那麽建出SAM後,求出parent樹上,每個點|Right|,然後走一遍找到對應的點,這個點的Right集合的大小就是答案。

  求Right可以從葉子結點往上走一遍。

  考慮動態加入,那麽會在parent樹上,增加一點,並且支持加邊刪邊,求一個點的權值,在一條到根的鏈上增加一個數,所以LCT維護parent樹。

代碼:

#include<cstdio>
#include<algorithm>
#include
<cstring> #include<iostream> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if
(ch==-)f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-0;return x*f; } const int N = 1200005; struct LCT{ int fa[N], ch[N][2], sk[N], top, tag[N], R[N]; inline void add(int x,int v) { if (x) R[x] += v, tag[x] += v; } inline void pushdown(int x) { if (tag[x]) add(ch[x][0
], tag[x]), add(ch[x][1], tag[x]), tag[x] = 0; } inline bool isroot(int x) { return ch[fa[x]][0] != x && ch[fa[x]][1] != x; } inline int son(int x) { return ch[fa[x]][1] == x; } inline void rotate(int x) { int y = fa[x], z = fa[y], c = son(y), b = son(x), a = ch[x][!b]; if (!isroot(y)) ch[z][c] = x; fa[x] = z; ch[x][!b] = y; fa[y] = x; ch[y][b] = a; if (a) fa[a] = y; } inline void splay(int x) { top = 1, sk[1] = x; for (int i = x; !isroot(i); i = fa[i]) sk[++top] = fa[i]; while (top) pushdown(sk[top --]); while (!isroot(x)) { int y = fa[x]; if (isroot(y)) rotate(x); else { if (son(x) == son(y)) rotate(y), rotate(x); else rotate(x), rotate(x); } } } inline void access(int x) { for (int last = 0; x; last = x, x = fa[x]) { splay(x); ch[x][1] = last; } } inline void link(int x,int y) { // 這是一棵有根樹,每條邊的方向確定(指向父節點),不需要makeroot,後面是取出這條鏈,打標記 fa[x] = y; access(y); splay(y); add(y, R[x]); } inline void cut(int x) { // x 和 fa[x] 斷開,fa[x]的深度小,所以是x的左兒子 access(x); splay(x); add(ch[x][0], -R[x]); fa[ch[x][0]] = 0; ch[x][0] = 0; } }lct; int ch[N][26], len[N], fa[N], Last = 1, Index = 1; void extend(int c) { int np = ++Index, p = Last; lct.R[np] = 1; for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np; if (!p) fa[np] = 1, lct.link(np, 1); else { int Q = ch[p][c]; if (len[Q] == len[p] + 1) fa[np] = Q, lct.link(np, Q); else { int NQ = ++Index; fa[NQ] = fa[Q]; lct.link(NQ, fa[Q]); len[NQ] = len[p] + 1; memcpy(ch[NQ], ch[Q], sizeof ch[Q]); fa[Q] = fa[np] = NQ; lct.cut(Q); lct.link(Q, NQ); lct.link(np, NQ); for (; p && ch[p][c] == Q; p = fa[p]) ch[p][c] = NQ; } } Last = np; } void build(char *s,int len) { for (int i = 0; i < len; ++i) extend(s[i] - A); } int find(char *s,int len) { int now = 1; for (int i = 0; i < len; ++i) { now = ch[now][s[i] - A]; if (!now) return 0; } lct.splay(now); return lct.R[now]; } void getstr(char *s,int x,int len) { for (int i = 0; i < len; ++i) { x = (x * 131 + i) % len; swap(s[i], s[x]); } } char s[N], opt[10]; int main() { int n = read(), L, lastans = 0, ans; scanf("%s", s); L = strlen(s); build(s, L); for (int i = 1; i <= n; ++i) { scanf("%s%s", opt, s); L = strlen(s); getstr(s, lastans, L); if (opt[0] == Q) { ans = find(s, L); lastans ^= ans; printf("%d\n", ans); } else build(s, L); } return 0; }

2555: SubString