bzoj2555 Substring

题意:给一个字符串后面加若干个字符串或询问某个串的出现次数。强在。

标程:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm> 
 4 using namespace std;
 5 const int N=1200005;
 6 int son[N][2],ch[N][26],tag[N],sum[N],pre[N],fa[N],sl,ans,mask,n,top,q[N],sc,last,l[N];
 7 char s[N];
 8 int is_rt(int x){return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;}
 9 void modi(int x,int y){tag[x]+=y;sum[x]+=y;}
10 void down(int x)
11 {
12     if (tag[x])
13     {
14         if (son[x][0]) modi(son[x][0],tag[x]);
15         if (son[x][1]) modi(son[x][1],tag[x]);
16         tag[x]=0; 
17     }
18 }
19 void rot(int x)
20 {
21    int y=fa[x],z=fa[y],l=(son[y][1]==x),r=l^1;
22    if (!is_rt(y)) son[z][(son[z][1]==y)]=x;
23    fa[x]=z;fa[y]=x;fa[son[x][r]]=y;
24    son[y][l]=son[x][r];son[x][r]=y;
25 }
26 void spl(int x)
27 {
28     q[top=1]=x;
29     for (int i=x;!is_rt(i);i=fa[i]) q[++top]=fa[i];
30     while (top) down(q[top--]);
31     for (int y;!is_rt(x);rot(x))
32       if (!is_rt(y=fa[x]))
33         if ((son[fa[y]][0]==y)^(son[y][0]==x)) rot(x);else rot(y); 
34 }
35 void accs(int x){for (int t=0;x;t=x,x=fa[x]) spl(x),son[x][1]=t;}
36 void link(int x,int y){fa[x]=y;accs(x);spl(x);}
37 void cut(int x,int y){accs(y);spl(y);fa[x]=son[y][1]=0;}//注意x比y的深度大,x应该在y的右子树 
38 void sam(int c)
39 {
40     int p=last,np=++sc;l[np]=l[p]+1;last=np;
41     for (;p&&!ch[p][c];p=pre[p]) ch[p][c]=np;
42     if (!p) pre[np]=1,link(np,1);//注意区分lct和Sam上的father不同 
43     else {
44         int q=ch[p][c];
45         if (l[q]==l[p]+1) pre[np]=q,link(np,q);
46         else {
47             int nq=++sc;l[nq]=l[p]+1;
48             memcpy(ch[nq],ch[q],sizeof(ch[q]));
49             spl(q);sum[nq]=sum[q]; 
50             pre[nq]=pre[q];
51             cut(q,pre[q]);link(nq,pre[q]);
52             pre[q]=pre[np]=nq;
53             link(q,nq);link(np,nq);
54             for (;p&&ch[p][c]==q;p=pre[p]) ch[p][c]=nq; 
55         }
56     }
57     accs(np);spl(np); 
58     modi(np,1);//np为关键点 
59 }
60 void secret(char *s,int mask)
61 {
62     sl=strlen(s);
63     for (int i=0;i<sl;i++)
64       mask=(mask*131+i)%sl,swap(s[i],s[mask]);
65 }
66 void qry(char *s)
67 {
68     int now=1;sl=strlen(s);
69     for (int i=0;i<sl;i++) now=ch[now][s[i]-'A'];
70     if (!now) puts("0");else spl(now),printf("%d\n",ans=sum[now]),mask^=ans;
71 }
72 int main()
73 {
74     scanf("%d%s",&n,s);sl=strlen(s);
75     sc=last=1;
76     for (int i=0;i<sl;i++) sam(s[i]-'A');
77     char op[10];
78     while (n--)
79     {
80         scanf("%s%s",op,s);secret(s,mask);
81         if (op[0]=='Q') qry(s);
82         else {
83            sl=strlen(s);
84            for (int i=0;i<sl;i++) sam(s[i]-'A');    
85         }
86     }
87     return 0;
88 }

题解:后缀自动机+lct

如果是离线就是二维数点问题。

在线的话,其实就是求right集合大小嘛,用有根lct动态维护sam的树边。

每次加入一个新点,就是在到根路径上都+1。打一个加标记即可。

猜你喜欢

转载自www.cnblogs.com/Scx117/p/8902879.html
今日推荐