洛谷P2414 [NOI2011]阿狸的打字机(AC自动机)

传送门

 

考虑一下,如果串B在串A中出现过,那么A的fail指针必定直接或间接指向B

那么我们可以把fail树建起来,那么就变成B代表的节点的子树里有多少节点属于A

然后这就是一个序列统计问题,直接用dfs序+树状数组可以维护

具体的操作就是,先把每一个点有关的询问给存起来,然后等到在trie树上一遍dfs,当dfs到这个串的结束节点说明所有有关这个串的节点都被遍历到(可以在遍历的时候顺便用树状数组维护序列和),然后对每一个询问查一下子树和即可

  1 //minamoto
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<queue>
  6 #include<algorithm>
  7 using namespace std;
  8 const int N=100005;
  9 int tot=1;
 10 struct node{
 11     int num,type;
 12     node(){}
 13     node(int num,int type):num(num),type(type){}
 14 };
 15 queue<node> q;
 16 int ch[N][26],End[N],word,fa[N],fail[N],dis[N];
 17 inline int insert(int p,int c){
 18     if(ch[p][c]) return ch[p][c];
 19     ch[p][c]=++tot,fa[tot]=p;return tot;
 20 }
 21 inline int back(int p){return fa[p];}
 22 inline void ed(int p){End[p]=++word,dis[word]=p;}
 23 void build(){
 24     for(int i=0;i<26;++i)
 25     if(ch[1][i])
 26     q.push(node(ch[1][i],i)),fail[ch[1][i]]=1;
 27     while(!q.empty()){
 28         node now=q.front();q.pop();
 29         if(fail[now.num]!=1){
 30             int trail=fail[fa[now.num]];
 31             while(true){
 32                 if(ch[trail][now.type]){trail=ch[trail][now.type];break;}
 33                 if(trail==1) break;trail=fail[trail];
 34             }
 35             fail[now.num]=trail;
 36         }
 37         for(int i=0;i<26;++i)
 38         if(ch[now.num][i])
 39         q.push(node(ch[now.num][i],i));
 40     }
 41 }
 42 int ver[N<<1],Next[N<<1],head[N],E=0;
 43 inline void add(int u,int v){
 44     ver[++E]=v,Next[E]=head[u],head[u]=E;
 45 }
 46 int ver1[N],Next1[N],head1[N],edge1[N],E1=0;
 47 inline void add1(int u,int v,int num){
 48     ver1[++E1]=v,Next1[E1]=head1[u],head1[u]=E1,edge1[E1]=num;
 49 }
 50 int c[N<<1];
 51 inline void addd(int x,int y){
 52     for(;x<=tot;x+=x&-x) c[x]+=y;
 53 }
 54 inline int sum(int x){
 55     int res=0;
 56     for(;x;x-=x&-x) res+=c[x];
 57     return res;
 58 }
 59 int dfn[N],sz[N],cnt=0,ans[N];
 60 bool book[N];
 61 void dfsfail(int u){
 62     dfn[u]=++cnt,sz[u]=1,book[u]=true;
 63     for(int i=head[u];i;i=Next[i]){
 64         int v=ver[i];
 65         if(!book[v]) dfsfail(v),sz[u]+=sz[v];
 66     }
 67 }
 68 void dfstrie(int u){
 69     addd(dfn[u],1);
 70     if(End[u]){
 71         for(int i=head1[End[u]];i;i=Next1[i]){
 72             int v=ver1[i],x=dis[v];
 73 //            printf("%d %d %d\n",v,x,edge1[i]);
 74             ans[edge1[i]]=sum(dfn[x]+sz[x]-1)-sum(dfn[x]-1);
 75         }
 76     }
 77     for(int i=0;i<26;++i)
 78     if(ch[u][i]) dfstrie(ch[u][i]);
 79     addd(dfn[u],-1);
 80 }
 81 char s[N];int len,m,st;
 82 int main(){
 83 //    freopen("testdata.in","r",stdin);
 84     scanf("%s",s+1);
 85     len=strlen(s+1);
 86     for(st=1;st<=len;++st)
 87     if(s[st]!='B'&&s[st]!='P') break;
 88     int p=insert(1,s[st]-'a');
 89     for(int i=st+1;i<=len;++i){
 90         if(s[i]=='B') p=back(p);
 91         else if(s[i]=='P') ed(p);
 92         else p=insert(p,s[i]-'a');
 93     }
 94     scanf("%d",&m);
 95     for(int i=1,u,v;i<=m;++i){
 96         scanf("%d%d",&u,&v);
 97         add1(v,u,i);
 98     }
 99     build();
100     for(int i=2;i<=tot;++i)
101     add(fail[i],i),add(i,fail[i]);
102     dfsfail(1),dfstrie(1);
103     for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
104     return 0;
105 }

 

posted @ 2018-09-13 20:45  bztMinamoto  阅读(179)  评论(0编辑  收藏  举报
Live2D