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 }

 

 
 
posted @ 2018-11-26 13:58  guapisolo  阅读(143)  评论(0编辑  收藏  举报