bzoj[3881]Divljak(dfs序+树状数组+fail树)

Posted lnxcj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj[3881]Divljak(dfs序+树状数组+fail树)相关的知识,希望对你有一定的参考价值。

这道题利用了fail树的神奇性质————父节点为其子节点的前缀

先对Alice的集合建一个fail树,

Bob每插入一个串,都将串在自动机上经过的点在树上打上标记(+1)

每次查询的答案就是询问串的结束节点的子树的贡献

所以还需要用到树状数组来维护dfs序

因为Bob的一个串至多只能对Alice的某一个串做出1的贡献,所以不能单纯加和

要对树链取并

可以将一个Bob串在fail树上经过的所有点按入栈顺序排序,相邻每两个点的lca贡献-1

可以证明,这样会使每次某个点的子树内没有重复贡献

  1 #include<queue>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 int n,m,cnt,tot,tp,num;
  7 char s[2000005];
  8 bool ed[2000005];
  9 int vis[2000005];
 10 int ed_pos[100005];
 11 int head[2000005];
 12 int fa[2000005];
 13 int dep[2000005];
 14 int grand[2000005];
 15 int siz[2000005];
 16 int son[2000005];
 17 int ad[4000005];
 18 int stk[4000005];
 19 int tmp[2000005];
 20 struct Trie{
 21     int son[26];
 22     int fail;
 23 }tr[2000005];
 24 struct Edge{
 25     int fr;
 26     int to;
 27     int nxt;
 28 }edge[2000005];
 29 struct node{
 30     int in;
 31     int out;
 32 }pos[2000005];
 33 int lowbit(int x){
 34     return x&(-x);
 35 }
 36 void init(){
 37     memset(head,-1,sizeof(head));
 38 }
 39 void addx(int x,int v){
 40     while(x<=2*tot){
 41         ad[x]+=v;
 42         x+=lowbit(x);
 43     }
 44 }
 45 int getsum(int x){
 46     int ret=0;
 47     while(x){
 48         ret+=ad[x];
 49         x-=lowbit(x);
 50     }
 51     return ret;
 52 }
 53 void addedge(int u,int v){
 54     edge[cnt].fr=u;
 55     edge[cnt].to=v;
 56     edge[cnt].nxt=head[u];
 57     head[u]=cnt++;
 58 }
 59 void insert(char h[],int mrk){
 60     int now=0;
 61     int len=strlen(h+1);
 62     for(int i=1;i<=len;i++){
 63         int k=h[i]-a;
 64         if(!tr[now].son[k])tr[now].son[k]=++tot;
 65         now=tr[now].son[k];
 66     }
 67     ed[now]=true;
 68     ed_pos[mrk]=now;
 69 }
 70 void getfail(){
 71     queue<int>que;
 72     for(int i=0;i<26;i++){
 73         if(tr[0].son[i]){
 74             addedge(0,tr[0].son[i]);
 75             que.push(tr[0].son[i]);
 76         }
 77     }
 78     while(!que.empty()){
 79         int u=que.front();
 80         que.pop();
 81         for(int i=0;i<26;i++){
 82             if(tr[u].son[i]){
 83                 tr[tr[u].son[i]].fail=tr[tr[u].fail].son[i];
 84                 addedge(tr[tr[u].fail].son[i],tr[u].son[i]);
 85                 que.push(tr[u].son[i]);
 86             }
 87             else tr[u].son[i]=tr[tr[u].fail].son[i];
 88         }
 89     }
 90 }
 91 void dfs1(int u){
 92     siz[u]=1;stk[++tp]=u;pos[u].in=tp;
 93     for(int i=head[u];i!=-1;i=edge[i].nxt){
 94         int v=edge[i].to;
 95         if(v==fa[u])continue;
 96         fa[v]=u;dep[v]=dep[u]+1;
 97         dfs1(v);siz[u]+=siz[v];
 98         if(siz[v]>siz[son[u]]||(!son[u]))son[u]=v;
 99     }
100     stk[++tp]=u;pos[u].out=tp;
101 }
102 void dfs2(int u){
103     if(u!=son[fa[u]])grand[u]=u;
104     else grand[u]=grand[fa[u]];
105     for(int i=head[u];i!=-1;i=edge[i].nxt){
106         int v=edge[i].to;
107         if(v==fa[u])continue;
108         dfs2(v);
109     }
110 }
111 int lca(int x,int y){
112     while(grand[x]!=grand[y]){
113         if(dep[grand[x]]<dep[grand[y]])swap(x,y);
114         x=fa[grand[x]];
115     }
116     if(dep[x]>dep[y])swap(x,y);
117     return x;
118 }
119 int cmp(int a,int b){
120     return pos[a].in<pos[b].in;
121 }
122 void match(char b[],int tim){
123     int now=0;
124     int len=strlen(s+1);
125     for(int i=1;i<=len;i++){
126         int k=b[i]-a;
127         now=tr[now].son[k];
128         if(vis[now]==tim)continue;
129         vis[now]=tim;tmp[++num]=now;
130     }
131     sort(tmp+1,tmp+num+1,cmp);
132     for(int i=1;i<=num;i++)addx(pos[tmp[i]].in,1);
133     for(int i=1;i<num;i++){
134         int f=lca(tmp[i],tmp[i+1]);
135         addx(pos[f].in,-1);
136     }
137 }
138 int main(){
139     init();
140     scanf("%d",&n);
141     for(int i=1;i<=n;i++){
142         scanf("%s",s+1);
143         insert(s,i);
144     }
145     getfail();dfs1(0);dfs2(0);
146     scanf("%d",&m);
147     for(int i=1;i<=m;i++){
148         int ac;
149         scanf("%d",&ac);
150         if(ac==1){
151             scanf("%s",s+1);
152             num=0;match(s,i);
153         }else{
154             int p;
155             scanf("%d",&p);
156             int ans=getsum(pos[ed_pos[p]].out)-getsum(pos[ed_pos[p]].in-1);
157             printf("%d
",ans);
158         }
159     }
160     return 0;
161 }

 

以上是关于bzoj[3881]Divljak(dfs序+树状数组+fail树)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3881: [Coci2015]Divljak

bzoj3881 [Coci2015]Divljak

[COCI2015] Divljak - AC自动机,DFS序,树状数组,LCA

bzoj 3881 [Coci2015]Divljak——LCT维护parent树链并

BZOJ3881 Coci2015 Divljak fail树+差分

BZOJ 1103 大都市(dfs序+树状数组)