bzoj2555: SubString

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <algorithm>
  6 #define maxn 1200005
  7 #define maxl 3000005
  8 using namespace std;
  9 
 10 int q,n,tot,root,last,mark,m,ri[maxn],lazy[maxn];
 11 char st[maxl];
 12 void watch(){
 13     int temp=mark;
 14     for (int i=1;i<=m;i++){
 15         temp=(temp*131+i-1)%m+1;
 16         char t=st[i]; st[i]=st[temp],st[temp]=t,temp--;
 17     }
 18 }
 19 struct Date{
 20     int fa[maxn],son[maxn][2];
 21     int which(int x){
 22         return son[fa[x]][1]==x;
 23     }
 24     bool isroot(int x){
 25         return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
 26     }
 27     void change(int x,int y){
 28         ri[x]+=y,lazy[x]+=y;
 29     }
 30     void pushdown(int x){
 31         if (lazy[x]==0) return;
 32         if (son[x][0]) change(son[x][0],lazy[x]);
 33         if (son[x][1]) change(son[x][1],lazy[x]);
 34         lazy[x]=0;
 35     }
 36     void relax(int x){
 37         if (!isroot(x)) relax(fa[x]);
 38         pushdown(x);
 39     }
 40     void rotata(int x){
 41         int y=fa[x],dd=which(y),d=which(x);
 42         if (!isroot(y)) son[fa[y]][dd]=x; fa[x]=fa[y];
 43         fa[son[x][d^1]]=y,son[y][d]=son[x][d^1];
 44         fa[y]=x,son[x][d^1]=y;
 45     }
 46     void splay(int x){
 47         relax(x);
 48         while (!isroot(x)){
 49             if (isroot(fa[x])) rotata(x);
 50             else if (which(x)==which(fa[x])) rotata(fa[x]),rotata(x);
 51             else rotata(x),rotata(x);
 52         }
 53     }
 54     void access(int x){
 55         for (int p=0;x;x=fa[x]){
 56             splay(x);
 57             son[x][1]=p;
 58             p=x;
 59         }
 60     }
 61     void link(int x,int y){
 62         fa[x]=y,access(y),splay(y),change(y,ri[x]);
 63     }
 64     void cut(int x){
 65         access(x),splay(x),change(son[x][0],-ri[x]),fa[son[x][0]]=0,son[x][0]=0;
 66     }
 67 }lct;
 68 struct Tsegment{
 69     int fa[maxn],son[maxn][26],dist[maxn];
 70     void prepare(){tot=root=last=1;memset(lazy,0,sizeof(lazy)); memset(ri,0,sizeof(ri));}
 71     int newnode(int x){
 72         dist[++tot]=x; return tot;
 73     }
 74     void add(int x){
 75         int p=last,np=newnode(dist[last]+1); last=np,ri[np]=1;
 76         for (;p&&!son[p][x];p=fa[p]) son[p][x]=np;
 77         if (p==0) fa[np]=root,lct.link(np,root);
 78         else{
 79             int q=son[p][x];
 80             if (dist[p]+1==dist[q]) fa[np]=q,lct.link(np,q);
 81             else{
 82                 int nq=newnode(dist[p]+1); ri[nq]=0;
 83                 memcpy(son[nq],son[q],sizeof(son[q]));
 84                 fa[nq]=fa[q]; lct.cut(q),lct.link(nq,fa[nq]);
 85                 fa[q]=fa[np]=nq; lct.link(q,nq),lct.link(np,nq);
 86                 for (;p&&son[p][x]==q;p=fa[p]) son[p][x]=nq;
 87             }
 88         }
 89     }
 90     void build(){
 91         for (int i=1;i<=m;i++) add(st[i]-'A');
 92     }
 93     void query(){
 94         int x,y;
 95         bool can=1;
 96         x=root;
 97         for (int i=1;i<=m;i++){
 98             y=st[i]-'A';
 99             if (!son[x][y]){
100                 can=0;
101                 break;
102             }else{
103                 x=son[x][y];
104             }
105         }
106         if (can==0||x==root) puts("0");
107         else{
108             lct.splay(x);
109             printf("%d\n",ri[x]),mark^=ri[x];
110         }
111     }
112 }SAM;
113 
114 int main(){
115     scanf("%d",&q),mark=0;
116     scanf("%s",st+1),m=strlen(st+1);
117     SAM.prepare();
118     SAM.build();
119     while (q--){
120         scanf("%s",st+1);
121         if (st[1]=='A') scanf("%s",st+1),m=strlen(st+1),watch(),SAM.build();
122         else scanf("%s",st+1),m=strlen(st+1),watch(),SAM.query();
123     }
124     return 0;
125 }
View Code

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2555

题目大意:给你一个字符串init,要求你支持两个操作
(1):在当前字符串的后面插入一个字符串
(2):询问字符串s在当前字符串中出现了几次?(作为连续子串)
你必须在线支持这些操作。

做法:如果没有操作1,显然kmp,ac自动机,后缀自动机都可以轻松解决,用后缀自动机的话,就是对原串建立SAM,匹配串在上面匹配,若失配,则输出0,否则一直跳,假设最后跳到了x节点,答案就是,这个状态的right值。right值为parent树中以该节点为根的子树中right值的和,静态的显然比较好维护,但本题是动态加串,由于SAM是用增量法构建的,显然可以维护这个SAM,但是right则不怎么好维护,看了题解后,发现parent树毕竟是一棵树,那显然可以用lct来维护right值。操作2与静态的类似。恶心的就是这题的解密。

后缀自动机+lct。

posted @ 2016-06-01 19:54  oyzx~  阅读(146)  评论(0编辑  收藏  举报