HDU 4641 K-string 后缀自动机 并查集
Posted 鲸头鹳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 4641 K-string 后缀自动机 并查集相关的知识,希望对你有一定的参考价值。
http://acm.hdu.edu.cn/showproblem.php?pid=4641
https://blog.csdn.net/asdfgh0308/article/details/40969047
给一个小写字母字符串,1 a表示在字符串尾部添加一个小写字母a,2 表示当前有多少种子串出现次数大于等于K。
求出现次数桶排序(说是拓扑排序也可以?)就阔以了,种类就是t[i].len-t[t[i].f].len。
在线处理是直接扫描,时间复杂度是O(树高*m)。
离线做法是先把所有添加操作都做完,然后去掉字母反向求子串种数,可以使用并查集降低时间复杂度(每个连通块中只有总父亲表示的子串对当前答案有贡献,保证了每个点的平均扫描次数)。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 #define LL long long 9 const int maxn=60100; 10 int n,m,K; 11 char ch[maxn*10],ch1[3]; 12 int e[maxn*4]={},b[maxn*5]={},siz; 13 struct nod{ 14 int sig[26],f,len; 15 }t[maxn*10]; int tot,la; 16 17 int cnt[maxn*10]={},rk[maxn*10]={}; 18 int fa[maxn*10]={},sub[maxn*10]={},g[maxn*10]={}; 19 LL ans[maxn*4]={}; 20 21 void addit(int z){ 22 int x=++tot,i=la; t[x].len=t[i].len+1; 23 b[siz]=x; 24 for(;i&&!t[i].sig[z];i=t[i].f)t[i].sig[z]=x; 25 if(!i)t[x].f=1; 26 else{ 27 int y=t[i].sig[z]; 28 if(t[y].len==t[i].len+1)t[x].f=y; 29 else{ 30 int p=++tot; 31 t[p]=t[y];t[p].len=t[i].len+1; 32 t[y].f=t[x].f=p; 33 for(;i&&t[i].sig[z]==y;i=t[i].f)t[i].sig[z]=p; 34 } 35 } 36 la=x; 37 } 38 void msort(){ 39 int i; 40 for(i=0;i<=siz;i++)cnt[i]=0; 41 for(i=2;i<=tot;i++)cnt[t[i].len]++; 42 for(i=1;i<=siz;i++)cnt[i]+=cnt[i-1]; 43 for(i=tot;i>1;i--)rk[cnt[t[i].len]--]=i; 44 } 45 int getfa(int x){ 46 int y=x,z; 47 while(y!=fa[y])y=fa[y]; 48 while(x!=fa[x]){ z=x; x=fa[x];fa[z]=y;} 49 return fa[x]; 50 } 51 int main(){ 52 int i,p,y; LL num; 53 while(~scanf("%d%d%d",&n,&m,&K)){ 54 memset(t,0,sizeof(t)); tot=1; la=1; siz=0; 55 scanf("%s",ch); 56 for(i=0;i<n;++i){ addit(ch[i]-‘a‘); ++siz; } 57 for(i=1;i<=m;i++){ 58 scanf("%d",&e[i]); 59 if(e[i]==1){ scanf("%s",ch1); addit(ch1[0]-‘a‘); ch[siz++]=ch1[0]; } 60 } 61 msort(); p=1,num=0; 62 for(i=1;i<=tot;i++){ g[i]=0; fa[i]=i; sub[i]=0;} 63 for(i=0;i<siz;++i){ p=t[p].sig[ch[i]-‘a‘]; ++g[p]; } 64 for(i=tot-1;i>0;i--){ p=rk[i]; if(t[p].f!=1)g[t[p].f]+=g[p]; } 65 for(i=2;i<=tot;++i){ if(g[i]>=K) num+=t[i].len-t[t[i].f].len; } 66 for(i=m;i>0;i--){ 67 if(e[i]==2)ans[i]=num; 68 else{ 69 p=b[--siz]; 70 y=getfa(p); 71 while(y!=1&&g[y]<K){ fa[y]=getfa(t[y].f); y=fa[y];} 72 y=getfa(p); 73 if(y==1)continue; 74 sub[y]++; 75 while(y!=1&&(g[y]-sub[y]<K)){ 76 num-=t[y].len-t[t[y].f].len; 77 p=getfa(t[y].f); 78 sub[p]+=sub[y]; fa[y]=p; 79 y=fa[y]; 80 } 81 } 82 } 83 for(i=1;i<=m;++i)if(e[i]==2)printf("%lld\n",ans[i]); 84 } 85 return 0; 86 }
以上是关于HDU 4641 K-string 后缀自动机 并查集的主要内容,如果未能解决你的问题,请参考以下文章