Live2d Test Env

CodeForces - 1207G :Indie Album(AC自动机 fail树上DFS)

题意:有N个串,给出的形式是拼接给出,对于第i行:  (1,c)表示字符串i是单个字母c; (2,p,c)表示字符串i=在字符串p后面接上一个字母c。

          然后给出M个提问,形式是(i,string)。问string在字符串i中出现了多少次。

思路:这类题显然是在AC自动机上乱搞。  对于询问的串建立AC自动机,BFS建立fail树;那么一个询问其实就是第i个串的位置到根的这些节点,有多少个在string节点的子树里。      即给一条链染色,然后询问一个点是子树里多少点被染色了。 为了不重不漏,  我们用回溯就可以处理了。 然后用树状数组维护DFS序下的前缀和。  

具体的,对于N个串在AC自动机上跑,每跑一步对应N个字符串之一。 每跑到一个节点,就加加。 跑完子树后就减减,保证了加的部分是一条链。 

#include<bits/stdc++.h>
#define pii pair<int,int>
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=400010;
vector<pii>G[maxn],Q[maxn];
vector<int>F[maxn];
int ch[maxn][26],fail[maxn],ans[maxn],tot;
int in[maxn],out[maxn],times; //dfn
char s[maxn]; int sum[maxn];
void add(int x,int val){ while(x<=times) sum[x]+=val,x+=(-x)&x;}
int query(int x){ int res=0; while(x){ res+=sum[x]; x-=(-x)&x; } return res;}
int add()
{
    int now=0,L=strlen(s);
    rep(i,0,L-1) {
        if(!ch[now][s[i]-'a']) ch[now][s[i]-'a']=++tot;
        now=ch[now][s[i]-'a'];
    }  return now;
}
void build()
{
    queue<int>q;
    rep(i,0,25) if(ch[0][i]) q.push(ch[0][i]);
    while(!q.empty()){
        int u=q.front(); q.pop();
        rep(i,0,25) {
            if(ch[u][i]){
                fail[ch[u][i]]=ch[fail[u]][i];
                q.push(ch[u][i]);
            }
            else ch[u][i]=ch[fail[u]][i];
        }
    }
    rep(i,1,tot) F[fail[i]].push_back(i);
}
void dfs(int u)
{
    in[u]=++times;
    for(int i=0;i<F[u].size();i++) dfs(F[u][i]);
    out[u]=times;
}
void dfs(int u,int now) //u是位置,now是id
{
    add(in[u],1);
    for(int i=0;i<Q[now].size();i++){
        pii t=Q[now][i];
        ans[t.second]=query(out[t.first])-query(in[t.first]-1);
    }
    for(int i=0;i<G[now].size();i++){
        pii t=G[now][i];
        dfs(ch[u][t.first],t.second);
    }
    add(in[u],-1);
}
int main()
{
    int N,M,opt,p;
    scanf("%d",&N);
    rep(i,1,N) {
        scanf("%d",&opt);
        if(opt==1) p=0;
        else scanf("%d",&p);
        scanf("%s",s);
        G[p].pb(pii(s[0]-'a',i));
    }
    scanf("%d",&M);
    rep(i,1,M) {
        scanf("%d%s",&p,s);
        Q[p].pb(pii(add(),i));
    }
    build();
    dfs(0);
    dfs(0,0);
    rep(i,1,M) printf("%d\n",ans[i]);
    return 0;
}

 

posted @ 2019-08-29 11:17  nimphy  阅读(441)  评论(0编辑  收藏  举报