[BZOJ]2555 Substring 后缀自动机&LCT

来源:互联网 发布:星际争霸2 剧情知乎 编辑:程序博客网 时间:2024/05/24 03:18

2555: SubString

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 3115  Solved: 925
[Submit][Status][Discuss]

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

2

A

QUERY B

ADD BBABBBBAAB

Sample Output


0

HINT

 40 % 的数据字符串最终长度 <= 20000,询问次数<= 1000,询问总长度<= 10000

    

100 % 的数据字符串最终长度 <= 600000,询问次数<= 10000,询问总长度<= 3000000


新加数据一组--2015.05.20

   

Source

Ctsc模拟赛By 洁妹

[Submit][Status][Discuss]


HOME Back

  hh代码题...要求动态插入当然是用sam啦... 由sam里的parent的性质可以得到, 一个串的出现次数就是在sam里面跑出来到的节点的在parent树里的子树siz, 也就是到达点的 |right|. 由于要动态插入并且sam中会有砍掉par边, 加入par边的操作... 于是就想到用lct来维护啦. 这道题是有向图都不用makeroot... 虽然说是代码题但还是挺好写的, 也就100行.

  需要注意的细节: 在访问一个节点的w一定要记得先把标记传下来, 要不然就会得到错误的答案。 话说样例查询不存在的串, 加了串后又不查询是有多水? 不过还是帮我查出re233. 一发AC一颗赛艇.

#include<bits/stdc++.h>using namespace std;const int maxn = 2e6 + 5;string chars;char ss[maxn];int top, root, tot, mask, last, Q, ans;int dep[maxn], w[maxn], tag[maxn], c[maxn][2], fa[maxn], s[maxn], a[maxn][26], par[maxn];inline void decr(int mask) {scanf("%s", ss);chars = ss;for (int j = 0; j < chars.length(); ++ j) {mask = (mask * 131 + j) % chars.length();char t = chars[j];chars[j] = chars[mask];chars[mask] = t;}}inline bool isroot(const int &x) {return c[fa[x]][0] != x && c[fa[x]][1] != x;}inline void add(int x, int val) {if (x) w[x] += val, tag[x] += val;}inline void pushdown(int x) {if (tag[x]) {add(c[x][0], tag[x]), add(c[x][1], tag[x]);tag[x] = 0;}}inline void rotate(int x) {int y = fa[x], z = fa[y];int l = (c[y][1] == x), r = l ^ 1;if (!isroot(y)) c[z][c[z][1] == y] = x;fa[x] = z, fa[y] = x, fa[c[x][r]] = y;c[y][l] = c[x][r], c[x][r] = y;}inline void splay(int x) {top = 0;s[++ top] = x;for (int i = x; !isroot(i); i = fa[i]) s[++ top] = fa[i];for (int i = top; i; -- i) pushdown(s[i]);for (int f; !isroot(x); rotate(x))if (!isroot(f = fa[x]))rotate((c[fa[f]][0] == f ^ c[f][0] == x) ? x : f);}inline void access(int x) {for (int t = 0; x; x = fa[x])splay(x), c[x][1] = t, t = x;}inline void link(int x, int y) {fa[x] = y, access(y), splay(y), add(y, w[x]);}inline void cut(int x) {access(x), splay(x), add(c[x][0], -w[x]);fa[c[x][0]] = 0, c[x][0] = 0;}inline int query() {decr(mask);int len = chars.length(), p = 1;for (int j = 0; j < len; ++ j)if (!(p = a[p][chars[j] - 'A'])) return 0;splay(p);return w[p];}inline void insert(int c) {int p = last, np = last = ++ tot;w[np] = 1, dep[np] = dep[p] + 1;while (p && !a[p][c]) a[p][c] = np, p = par[p];if (!p) par[np] = root, link(np, root);else {int q = a[p][c];if (dep[q] == dep[p] + 1) par[np] = q, link(np, q);else {int nq = ++ tot;dep[nq] = dep[p] + 1;par[nq] = par[q], link(nq, par[q]);memcpy(a[nq], a[q], sizeof(a[q]));par[np] = par[q] = nq;cut(q), link(q, nq), link(np, nq);while (a[p][c] == q) a[p][c] = nq, p = par[p];}}}int main() {root = last = ++ tot;scanf("%d", &Q);scanf("%s", ss);for (register int i = 0; ss[i]; ++ i)insert(ss[i] - 'A');for (register int i = 0; i < Q; ++ i) {scanf("%s", ss);if (ss[0] == 'A') {decr(mask);int len = chars.length();for (int j = 0; j < len; ++ j)insert(chars[j] - 'A');} else {ans = query(), mask ^= ans;printf("%d\n", ans);}}}