BZOJ5408: string(广义后缀自动机,LCT)

传送门

解题思路:

首先在后缀树上,确定了一个节点就相当于确定了一个串,那么一个点对应的串在另外一个点对应的串产生贡献,当且仅当这个点在当前点子树内。

那么考虑一个新的点在串中对串答案的贡献在一条树链上或者反过来说,就是产生贡献的点在这个点子树内。

才知道自己写的广义后缀自动机板子是错的QAQ

考虑n非常小,贡献可以单独算,再配合BZOJ2555的启发,这道题就可以使用LCT轻松地解决了。

代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define lll tr[spc].ch[0]
  5 #define rrr tr[spc].ch[1]
  6 #define ls ch[0]
  7 #define rs ch[1]
  8 typedef long long lnt;
  9 struct trnt{
 10     int ch[2];
 11     int fa;
 12     int val[21];
 13     int lzt[21];
 14     bool anc;
 15 }tr[1000000];
 16 struct sant{
 17     int tranc[26];
 18     int pre;
 19     int len;
 20 }s[1000000];
 21 int n,m;
 22 lnt sum;
 23 int siz;
 24 int type;
 25 int lastans;
 26 int pos[21][200010];
 27 char str[400000];
 28 bool whc(int spc)
 29 {
 30     return tr[tr[spc].fa].rs==spc;
 31 }
 32 void add(int spc,int no,int v)
 33 {
 34     if(!spc)return ;
 35     tr[spc].val[no]+=v;
 36     tr[spc].lzt[no]+=v;
 37     return ;
 38 }
 39 void pushdown(int spc)
 40 {
 41     for(int i=1;i<=n;i++)
 42     {
 43         if(tr[spc].lzt[i])
 44         {
 45             add(lll,i,tr[spc].lzt[i]);
 46             add(rrr,i,tr[spc].lzt[i]);
 47             tr[spc].lzt[i]=0;
 48         }
 49     }
 50 }
 51 void recal(int spc)
 52 {
 53     if(!tr[spc].anc)recal(tr[spc].fa);
 54     pushdown(spc);
 55     return ;
 56 }
 57 void rotate(int spc)
 58 {
 59     int f=tr[spc].fa;
 60     bool k=whc(spc);
 61     tr[f].ch[k]=tr[spc].ch[!k];
 62     tr[spc].ch[!k]=f;
 63     if(tr[f].anc)
 64     {
 65         tr[f].anc=false;
 66         tr[spc].anc=true;
 67     }else tr[tr[f].fa].ch[whc(f)]=spc;
 68     tr[spc].fa=tr[f].fa;
 69     tr[f].fa=spc;
 70     tr[tr[f].ch[k]].fa=f;
 71     return ;
 72 }
 73 void splay(int spc)
 74 {
 75     recal(spc);
 76     while(!tr[spc].anc)
 77     {
 78         int f=tr[spc].fa;
 79         if(tr[f].anc)
 80         {
 81             rotate(spc);
 82             return ;
 83         }
 84         if(whc(spc)^whc(f))rotate(spc);
 85         else rotate(f);
 86         rotate(spc);
 87     }
 88     return ;
 89 }
 90 void access(int spc)
 91 {
 92     int lst=0;
 93     while(spc)
 94     {
 95         splay(spc);
 96         tr[rrr].anc=true;
 97         tr[lst].anc=false;
 98         rrr=lst;
 99         lst=spc;
100         spc=tr[spc].fa;
101     }
102     return ;
103 }
104 void ADD(int from,int to,int cmd)
105 {
106     recal(from);
107     for(int i=1;i<=n;i++)
108     {
109         if(tr[from].val[i])
110         {
111             add(to,i,tr[from].val[i]*cmd);
112         }
113     }
114     return ;
115 }
116 void link(int x,int f)
117 {
118     access(f);
119     splay(f);
120     splay(x);
121     ADD(x,f,1);
122     tr[x].fa=f;
123     return ;
124 }
125 void cut(int spc)
126 {
127     access(spc);
128     splay(spc);
129     int spc_=lll;
130     lll=tr[spc_].fa=0;
131     tr[spc_].anc=true;
132     splay(spc_);
133     ADD(spc,spc_,-1);
134     return ;
135 }
136 int decode(int c)
137 {
138     if(type)return (c xor lastans)%10;
139     return c;
140 }
141 int Insert(int fin,int no,int c)
142 {
143     if(s[fin].tranc[c]&&s[s[fin].tranc[c]].len==s[fin].len+1)
144     {
145         int spc=s[fin].tranc[c];
146         access(spc);
147         splay(spc);
148         add(spc,no,1);
149         return spc;
150     }
151     int nwp,lsp,nwq,lsq,flag=0;
152     nwp=++siz;tr[nwp].val[no]=1;
153     s[nwp].len=s[fin].len+1;
154     for(lsp=fin;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre)s[lsp].tranc[c]=nwp;
155     if(!lsp)
156     {
157         s[nwp].pre=1;
158         link(nwp,1);
159     }else{
160         lsq=s[lsp].tranc[c];
161         if(s[lsq].len==s[lsp].len+1)
162         {
163             s[nwp].pre=lsq;
164             link(nwp,lsq);
165         }else{
166             if(s[nwp].len==s[lsp].len+1)flag=1;
167             nwq=++siz;
168             s[nwq]=s[lsq];
169             s[nwq].len=s[lsp].len+1;
170             s[nwp].pre=s[lsq].pre=nwq;
171             cut(lsq);
172             link(nwq,s[nwq].pre);
173             link(nwp,nwq);
174             link(lsq,nwq);
175             while(s[lsp].tranc[c]==lsq)
176             {
177                 s[lsp].tranc[c]=nwq;
178                 lsp=s[lsp].pre;
179             }
180         }
181     }
182     sum+=s[nwp].len-s[s[nwp].pre].len;
183     if(flag)return nwq;
184     return nwp;
185 }
186 void init(void)
187 {
188     for(int i=1;i<=500000;i++)tr[i].anc=true;
189     siz=1;
190     return ;
191 }
192 int query(char *a)
193 {
194     int len=strlen(a+1);
195     int spc=1;
196     for(int i=1;i<=len;i++)
197     {
198         int c=a[i]-'0';
199         spc=s[spc].tranc[c];
200         if(!spc)return 0;
201     }
202     int ans=-1;
203     recal(spc);
204     for(int i=1;i<=n;i++)
205         ans=std::max(ans,tr[spc].val[i]);
206     return ans;
207 }
208 int main()
209 {
210     scanf("%d%d",&n,&type);
211     init();
212     for(int i=1;i<=n;i++)
213     {
214         scanf("%s",str+1);
215         int len=strlen(str+1);
216         pos[i][0]=1;
217         for(int j=1;j<=len;j++)
218             pos[i][0]=Insert(pos[i][0],i,str[j]-'0');
219     }
220     scanf("%d",&m);
221     for(int r=1;r<=m;r++)
222     {
223         for(int i=1;i<=n;i++)pos[i][r]=pos[i][r-1];
224         int opt;
225         scanf("%d",&opt);
226         if(opt==1)
227         {
228             int x,y;
229             scanf("%d%d",&x,&y);
230             y=decode(y);
231             pos[x][r]=Insert(pos[x][r],x,y);
232         }
233         if(opt==2)
234         {
235             int x,y,z;
236             scanf("%d%d%d",&x,&y,&z);
237             int spc=pos[x][y];
238             recal(spc);
239             lastans=tr[spc].val[z];
240             printf("%d\n",lastans);
241         }
242         if(opt==3)printf("%lld\n",sum);
243         if(opt==4)
244         {
245             scanf("%s",str+1);
246             lastans=query(str);
247             printf("%d\n",lastans);
248         }
249     }
250     return 0;
251 }

转载于:https://www.cnblogs.com/blog-Dr-J/p/10440737.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>