2555: SubString
Description
懒得写背景了,给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。
Input
第一行一个数Q表示操作个数
第二行一个字符串表示初始字符串init
接下来Q行,每行2个字符串Type,Str
Type是ADD的话表示在后面插入字符串。
Type是QUERY的话表示询问某字符串在当前字符串中出现了几次。
为了体现在线操作,你需要维护一个变量mask,初始值为0
读入串Str之后,使用这个过程将之解码成真正询问的串TrueStr。
询问的时候,对TrueStr询问后输出一行答案Result
然后mask = mask xor Result
插入的时候,将TrueStr插到当前字符串后面即可。
HINT:ADD和QUERY操作的字符串都需要解压
Output
Sample Input
A
QUERY B
ADD BBABBBBAAB
Sample Output
0
HINT
40 % 的数据字符串最终长度 <= 20000,询问次数<= 1000,询问总长度<= 10000
100 % 的数据字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000
新加数据一组--2015.05.20
询问一个串在母串中的出现次数
即 询问该串在母串的后缀自动机上所到达状态的Right集合的大小
后缀自动机上一个状态的Right集合大小即为该状态在parent树中所有儿子的Right的和
即该状态的叶子节点个数(叶子节点的Right集合大小为1)
对母串建后缀自动机,LCT动态维护每个状态的Right集合大小即可
#include #include #include using namespace std; const int MaxN = 3000003; const int MaxC = 600006; int n, mask; char s[MaxN]; namespace Link_Cut_Tree { struct point { int l, r, fa; int key, add; inline point () {}; inline point (const int &x) { l = r = fa = 0; add = 0, key = x; } #define fa(x) P[x].fa #define l(x) P[x].l #define r(x) P[x].r #define key(x) P[x].key #define add(x) P[x].add }P[MaxC << 1]; int que[MaxC << 1], qr; inline bool isRoot(const int &x) { return !fa(x) || l(fa(x)) != x && r(fa(x)) != x; } inline bool which(const int &x) { return r(fa(x)) == x; } inline void Add(const int &x, const int &y) { key(x) += y, add(x) += y; } inline void Down(const int &x) { if (add(x)) { if (l(x)) Add(l(x), add(x)); if (r(x)) Add(r(x), add(x)); add(x) = 0; } } inline void Turn(const int &x) { int y = fa(x), z = fa(y), w = (l(y) == x ? r(x) : l(x)); fa(x) = z; if (!isRoot(y)) (l(z) == y ? l(z) : r(z)) = x; fa(y) = x, (l(y) == x ? r(x) : l(x)) = y; if (w) fa(w) = y; (l(y) == x ? l(y) : r(y)) = w; } inline void Splay(const int &x) { que[qr = 0] = x; for (int y = x; !isRoot(y); y = fa(y)) que[++qr] = fa(y); for (; qr >= 0; --qr) Down(que[qr]); while (!isRoot(x)) { if (!isRoot(fa(x))) { if (which(fa(x)) == which(x)) Turn(fa(x)); else Turn(x); } Turn(x); } } inline void Acess(const int &x) { int y = 0, z = x; for (; z; y = z, z = fa(z)) Splay(z), r(z) = y; Splay(x); } inline void Link(const int &x, const int &y) { fa(x) = y, Acess(y), Add(y, key(x)); } inline void Cut(const int &x) { Acess(x), Add(l(x), -key(x)); fa(l(x)) = 0, l(x) = 0; } } inline void Get(int mask) { scanf("%s", s); int len = strlen(s); for (int i = 0; s[i]; ++i) { mask = (mask * 131 + i) % len; swap(s[i], s[mask]); } } #define LCT Link_Cut_Tree namespace Suffix_Automaton { int root, last, cnt; struct SAM { int to[26]; int Max, par; #define Max(x) A[x].Max #define par(x) A[x].par }A[MaxC << 1]; inline void Init(const int &x, const int &m, const int &w) { for (int i = 0; i < 26; ++i) A[x].to[i] = 0; Max(x) = m; LCT :: P[x] = LCT :: point(w); } inline void SAMInit() { root = last = cnt = 1; Init(1, 0, 0); } inline void Extend(const int &c) { int p = last, np = last = ++cnt; Init(np, Max(p) + 1, 1); while (p && !A[p].to[c]) A[p].to[c] = np, p = par(p); if (!p) par(np) = root, LCT :: Link(np, root); else { int q = A[p].to[c]; if (Max(q) == Max(p) + 1) par(np) = q, LCT :: Link(np, q); else { int nq = ++cnt; Init(nq, Max(p) + 1, 0); for (int i = 0; i < 26; ++i) A[nq].to[i] = A[q].to[i]; par(nq) = par(q), LCT :: Link(nq, par(q)); LCT :: Cut(q), LCT :: Link(q, nq), LCT :: Link(np, nq); par(np) = par(q) = nq; while (A[p].to[c] == q) A[p].to[c] = nq, p = par(p); } } } inline void Build() { SAMInit(); scanf("%s", s); for (int i = 0; s[i]; ++i) Extend(s[i] - 'A'); } inline void Insert() { Get(mask); for (int i = 0; s[i]; ++i) Extend(s[i] - 'A'); } inline int Query() { Get(mask); int u = root; for (int i = 0; s[i]; ++i) { int c = s[i] - 'A'; if (!A[u].to[c]) return 0; else u = A[u].to[c]; } LCT :: Splay(u); return LCT :: key(u); } } int main() { scanf("%d", &n); Suffix_Automaton :: Build(); for (int i = 1; i <= n; ++i) { scanf("%s", s); if (s[0] == 'A') Suffix_Automaton :: Insert(); else { int res = Suffix_Automaton :: Query(); mask ^= res; printf("%d\n", res); } } }#include #include #include using namespace std; const int MaxN = 3000003; const int MaxC = 600006; int n, mask; char s[MaxN]; namespace Link_Cut_Tree { struct point { point *l, *r, *fa; int key, add; point (); }*null = new point; inline point :: point () { l = r = fa = null; add = key = 0; } point *que[MaxC << 1]; int qr; inline bool isRoot(point *x) { return !x -> fa || x -> fa -> l != x && x -> fa -> r != x; } inline bool which(point *x) { return x -> fa -> r == x; } inline void Add(point *x, const int &y) { x -> key += y, x -> add += y; } inline void Down(point *x) { if (x -> add) { if (x -> l) Add(x -> l, x -> add); if (x -> r) Add(x -> r, x -> add); x -> add = 0; } } inline void Turn(point *x) { point *y = x -> fa, *z = y -> fa; point *w = y -> l == x ? x -> r : x -> l; x -> fa = z; if (!isRoot(y)) (z -> l == y ? z -> l : z -> r) = x; y -> fa = x, (y -> l == x ? x -> r : x -> l) = y; if (w) w -> fa = y; (y -> l == x ? y -> l : y -> r) = w; } inline void Splay(point *x) { que[qr = 0] = x; for (point *y = x; !isRoot(y); y = y -> fa) que[++qr] = y -> fa; for (; qr >= 0; --qr) Down(que[qr]); while (!isRoot(x)) { if (!isRoot(x -> fa)) { if (which(x -> fa) == which(x)) Turn(x -> fa); else Turn(x); } Turn(x); } } inline void Acess(point *x) { point *y = null, *z = x; for (; z; y = z, z = z -> fa) Splay(z), z -> r = y; Splay(x); } inline void Link(point *x, point *y) { x -> fa = y, Acess(y), Add(y, x -> key); } inline void Cut(point *x) { Acess(x), Add(x -> l, -x -> key); x -> l -> fa = 0, x -> l = 0; } } inline void Get(int mask) { scanf("%s", s); int len = strlen(s); for (int i = 0; s[i]; ++i) { mask = (mask * 131 + i) % len; swap(s[i], s[mask]); } } #define LCT Link_Cut_Tree namespace Suffix_Automaton { struct SAM { SAM *to[26], *par; LCT :: point *tree; int Max; SAM (const int &M = 0, const int &w = 0) { for (int i = 0; i < 26; ++i) to[i] = NULL; par = NULL; Max = M; tree = new LCT :: point; tree -> key = w; } }*root = new SAM, *last = root; inline void Extend(const int &c) { SAM *p = last, *np = new SAM(p -> Max + 1, 1); while (p && !p -> to[c]) p -> to[c] = np, p = p -> par; if (!p) np -> par = root, LCT :: Link(np -> tree, root -> tree); else { SAM *q = p -> to[c]; if (q -> Max == p -> Max + 1) np -> par = q, LCT :: Link(np -> tree, q -> tree); else { SAM *nq = new SAM(p -> Max + 1, 0); for (int i = 0; i < 26; ++i) nq -> to[i] = q -> to[i]; nq -> par = q -> par, LCT :: Link(nq -> tree, q -> par -> tree); LCT :: Cut(q -> tree), LCT :: Link(q -> tree, nq -> tree), LCT :: Link(np -> tree, nq -> tree); np -> par = q -> par = nq; while (p && p -> to[c] == q) p -> to[c] = nq, p = p -> par; } } last = np; } inline void Insert() { for (int i = 0; s[i]; ++i) Extend(s[i] - 'A'); } inline int Query() { SAM *u = root; for (int i = 0; s[i]; ++i) { int c = s[i] - 'A'; if (!u -> to[c]) return 0; else u = u -> to[c]; } LCT :: Splay(u -> tree); return u -> tree -> key; } } int main() { scanf("%d", &n); scanf("%s", s); Suffix_Automaton :: Insert(); for (int i = 1; i <= n; ++i) { scanf("%s", s); if (s[0] == 'A') { Get(mask); Suffix_Automaton :: Insert(); } else { Get(mask); int res = Suffix_Automaton :: Query(); mask ^= res; printf("%d\n", res); } } }