bzoj3881 [Coci2015]Divljak
Posted AntiLeaf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3881 [Coci2015]Divljak相关的知识,希望对你有一定的参考价值。
我好菜啊……这种题都不会做……lrd给我讲了之后我才会的……
不难想到对所有询问串建AC自动机,然后可以在每次加进来一个文本串时维护一下答案,询问的时候直接回答。
每次扔进来一个文本串的时候fail树上经过的节点到根节点的所有节点的出现次数都会+1,但注意有很多节点会被算重了,这时就需要搞一个树链的并。
首先把节点按fail树的dfs序排序,每个点的标记+1,相邻两个节点的LCA处标记-1。不难看出来这样刚好可以不重不漏覆盖树链的并的所有点,这样询问时直接子树求和即可。因为需要动态维护区间和,所以要用到树状数组。
1 /************************************************************** 2 Problem: 3881 3 User: _Angel_ 4 Language: C++ 5 Result: Accepted 6 Time:14220 ms 7 Memory:506028 kb 8 ****************************************************************/ 9 #include<cstdio> 10 #include<cstring> 11 #include<algorithm> 12 #include<vector> 13 using namespace std; 14 const int maxn=100010,maxm=2000010; 15 int insert(const char*); 16 void getfail(); 17 void dfs(int); 18 void match(const char*); 19 int LCA(int,int); 20 void add(int,int); 21 int query(int); 22 bool cmp(int,int); 23 int ch[maxm][26]={{0}},f[maxm][26]={{0}},q[maxm]={0},sum[maxm]={0},cnt=0; 24 vector<int>G[maxm]; 25 int dfn[maxm],finish[maxm],tim=0,d[maxm]={0},c[maxm]={0},a[maxm]; 26 char s[maxm]; 27 int n,m,lgn=0,iter[maxn],t,x; 28 int main(){ 29 scanf("%d",&n); 30 for(int i=1;i<=n;i++){ 31 scanf("%s",s); 32 iter[i]=insert(s); 33 } 34 getfail(); 35 dfs(0); 36 for(int j=1;j<=lgn;j++)for(int i=1;i<=cnt;i++)f[i][j]=f[f[i][j-1]][j-1]; 37 scanf("%d",&m); 38 while(m--){ 39 scanf("%d",&t); 40 if(t==1){ 41 scanf("%s",s); 42 match(s); 43 } 44 else{ 45 scanf("%d",&x); 46 x=iter[x]; 47 printf("%d\\n",query(finish[x])-query(dfn[x]-1)); 48 } 49 } 50 return 0; 51 } 52 int insert(const char *c){ 53 int x=0; 54 while(*c){ 55 if(!ch[x][*c-\'a\'])ch[x][*c-\'a\']=++cnt; 56 x=ch[x][*c++-\'a\']; 57 } 58 return x; 59 } 60 void getfail(){ 61 int x,head=0,tail=0; 62 for(int c=0;c<26;c++)if(ch[0][c])q[tail++]=ch[0][c]; 63 while(head!=tail){ 64 x=q[head++];//printf("x=%d fail=%d\\n",x,f[x][0]); 65 G[f[x][0]].push_back(x); 66 fill(f[x]+1,f[x]+26,cnt+1); 67 for(int c=0;c<26;c++){ 68 if(ch[x][c]){ 69 int y=f[x][0]; 70 while(y&&!ch[y][c])y=f[y][0]; 71 f[ch[x][c]][0]=ch[y][c]; 72 q[tail++]=ch[x][c]; 73 } 74 else ch[x][c]=ch[f[x][0]][c]; 75 } 76 } 77 fill(f[0],f[0]+26,cnt+1); 78 } 79 void dfs(int x){//printf("dfs(%d)\\n",x); 80 dfn[x]=++tim; 81 d[x]=d[f[x][0]]+1; 82 while((1<<lgn)<d[x])lgn++; 83 for(int i=0;i<(int)G[x].size();i++)dfs(G[x][i]); 84 finish[x]=tim; 85 } 86 void match(const char *c){ 87 int x=0; 88 a[0]=0; 89 while(*c){ 90 x=ch[x][*c++-\'a\']; 91 a[++a[0]]=x; 92 } 93 sort(a+1,a+a[0]+1,cmp); 94 add(dfn[a[1]],1); 95 for(int i=2;i<=a[0];i++){ 96 add(dfn[LCA(a[i],a[i-1])],-1); 97 add(dfn[a[i]],1); 98 } 99 } 100 int LCA(int x,int y){//printf("LCA(%d,%d)=",x,y); 101 if(d[x]!=d[y]){ 102 if(d[x]<d[y])swap(x,y); 103 for(int i=lgn;i>=0;i--)if(d[f[x][i]]>=d[y])x=f[x][i]; 104 } 105 if(x==y)return x; 106 for(int i=lgn;i>=0;i--)if(f[x][i]!=f[y][i]){ 107 x=f[x][i]; 108 y=f[y][i]; 109 } 110 return f[x][0]; 111 } 112 void add(int x,int d){ 113 while(x<=tim){ 114 c[x]+=d; 115 x+=x&-x; 116 } 117 } 118 int query(int x){ 119 int ans=0; 120 while(x){ 121 ans+=c[x]; 122 x&=x-1; 123 } 124 return ans; 125 } 126 bool cmp(int x,int y){return dfn[x]<dfn[y];}
以上是关于bzoj3881 [Coci2015]Divljak的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 3881 [Coci2015]Divljak——LCT维护parent树链并
BZOJ3881 Coci2015 Divljak fail树+差分