BZOJ 3881 [COCI2015]Divljak (Trie图+Fail树+树链的并+树状数组维护dfs序)
题目大意:
Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的。
接下来会发生q个操作,操作有两种形式:
“1 P”,Bob往自己的集合里添加了一个字符串P。
“2 x”,Alice询问Bob,集合T中有多少个字符串包含串S_x。(我们称串A包含串B,当且仅当B是A的子串)
Bob遇到了困难,需要你的帮助。
最先想歪了,想把$T$里的串建自动机,最后失败了..
正解是对Alice的字符串建AC自动机,再建$Fail$树
那么对于操作1,每加入一个字符串,就把这个串放到AC自动机上跑
再把路径上的所有点记下来,新加入的字符串会对连接这些节点的树链上的所有点产生1点贡献
即求树链的并,用树状数组维护$dfs$序
先把这些节点按照$dfs$序排序,然后在树上打差分,树状数组维护前缀和,单点修改
每个节点都+1,$dfs$序中相邻节点的$lca$-1,最后在全局$lca$的父节点-1
询问就是子树查询
1 #include <cmath> 2 #include <queue> 3 #include <vector> 4 #include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 #define NN 2001000 8 #define MM 1510 9 #define ll long long 10 #define dd double 11 #define uint unsigned int 12 #define mod 1000000007 13 #define idx(X) (X-'a') 14 #define eps (1e-9) 15 using namespace std; 16 17 int n,m,cte; 18 int head[NN]; 19 struct Edge{int to,nxt;}edge[NN]; 20 void ae(int u,int v){ 21 cte++;edge[cte].nxt=head[u]; 22 head[u]=cte,edge[cte].to=v; 23 } 24 struct BIT{ 25 int sum[NN*2],tot; 26 void update(int x,int w){ 27 for(int i=x;i<=tot;i+=(i&(-i))) 28 sum[i]+=w;} 29 int query(int x){ 30 int ans=0; 31 for(int i=x;i>0;i-=(i&(-i))) 32 ans+=sum[i]; 33 return ans;} 34 }b; 35 namespace AC{ 36 int ch[NN][26],fail[NN],tot,ed[NN],dep[NN]; 37 void Build_Trie(char *str,int len,int id) 38 { 39 int x=0; 40 for(int i=1;i<=len;i++){ 41 if(!ch[x][idx(str[i])]) 42 ch[x][idx(str[i])]=++tot, 43 dep[tot]=dep[x]+1; 44 x=ch[x][idx(str[i])]; 45 }ed[id]=x; 46 } 47 void Build_Fail() 48 { 49 queue<int>q; 50 for(int i=0;i<26;i++) 51 if(ch[0][i]) q.push(ch[0][i]); 52 while(!q.empty()) 53 { 54 int x=q.front();q.pop(); 55 ae(fail[x],x); 56 for(int i=0;i<26;i++) 57 { 58 if(ch[x][i]){ 59 fail[ch[x][i]]=ch[fail[x]][i]; 60 q.push(ch[x][i]); 61 }else{ 62 ch[x][i]=ch[fail[x]][i]; 63 } 64 } 65 } 66 } 67 }; 68 char str[NN]; 69 namespace T{ 70 int son[NN],sz[NN],tp[NN],fa[NN],dep[NN]; 71 int st[NN],ed[NN],tot; 72 void dfs1(int u,int dad) 73 { 74 for(int j=head[u];j;j=edge[j].nxt){ 75 int v=edge[j].to; 76 if(v==dad) continue; 77 fa[v]=u;dep[v]=dep[u]+1; 78 dfs1(v,u); 79 son[u]=sz[v]>sz[son[u]]?v:son[u]; 80 }sz[u]++; 81 } 82 void dfs2(int u) 83 { 84 st[u]=++tot; 85 if(son[u]) tp[son[u]]=tp[u],dfs2(son[u]); 86 for(int j=head[u];j;j=edge[j].nxt){ 87 int v=edge[j].to; 88 if(v==fa[u]||v==son[u]) continue; 89 tp[v]=v,dfs2(v); 90 }ed[u]=++tot; 91 } 92 int LCA(int x,int y) 93 { 94 while(tp[x]!=tp[y]){ 95 if(dep[tp[x]]<dep[tp[y]]) swap(x,y); 96 x=fa[tp[x]]; 97 }return dep[x]<dep[y]?x:y; 98 } 99 int stk[NN],num; 100 int cmp(int x,int y){return st[x]<st[y];} 101 void update(char *str,int len) 102 { 103 int x=0,y,ff,v; 104 for(int i=1;i<=len;i++){ 105 v=AC::ch[x][idx(str[i])]; 106 if((!v)) break; 107 x=v;stk[++num]=x; 108 } 109 sort(stk+1,stk+num+1,cmp); 110 x=stk[1]; 111 if(num==1){ 112 b.update(st[x],1); 113 b.update(st[fa[x]],-1); 114 }else{ 115 b.update(st[x],1); 116 for(int i=2;i<=num;i++) 117 { 118 y=stk[i];ff=LCA(x,y); 119 b.update(st[y],1); 120 b.update(st[ff],-1); 121 x=stk[i]; 122 }ff=LCA(stk[1],stk[num]); 123 b.update(st[fa[ff]],-1); 124 } 125 while(num) stk[num--]=0; 126 } 127 int query(int x) 128 {return b.query(ed[x])-b.query(st[x]-1);} 129 void solve() 130 { 131 dep[0]=1;dfs1(0,-1); 132 tp[0]=0;dfs2(0); 133 scanf("%d",&m); 134 int fl,x; 135 b.tot=tot; 136 for(int i=1;i<=m;i++) 137 { 138 scanf("%d",&fl); 139 if(fl==1){ 140 scanf("%s",str+1); 141 int len=strlen(str+1); 142 update(str,len); 143 }else{ 144 scanf("%d",&x); 145 printf("%d\n",query(AC::ed[x])); 146 } 147 } 148 } 149 }; 150 151 152 int main() 153 { 154 scanf("%d",&n); 155 for(int i=1;i<=n;i++){ 156 scanf("%s",str+1); 157 int len=strlen(str+1); 158 AC::Build_Trie(str,len,i); 159 }AC::Build_Fail(); 160 T::solve(); 161 return 0; 162 }