[Coci2015]Divljak

 题目描述 

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遇到了困难,需要你的帮助。
题解
多串匹配问题,可以想到用AC自动机维护。
对于这种询问,每个串至多贡献一次的问题。
先是把每个T串在AC自动机上跑一遍,获得了一个点集,那么这些点在fail树上到根的路径上的所有点都会被贡献一次。
相当于这些链的并都被贡献了。
那我们的任务就是求链并。
一种方法是将所有点排一个序,然后对每个点到根的路径上加1,相邻两个点的LCA处-1。
链加不太好写,可以转化成统计子树和的形式,用BIT维护。
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define N 2000002
using namespace std;
typedef long long ll;
queue<int>q;
int tot,ch[N][26],head[N],f[N],zh[N],topp,n,tr[N],tag[N],size[N],deep[N],fa[N],son[N],top[N],dfn[N],dfnn,tott,fan[N];
char s[N];
inline ll rd(){
    ll x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
struct edge{int n,to;}e[N];
inline void add(int u,int v){
e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
inline void get_fail(){
    for(int i=0;i<26;++i)if(ch[0][i]){q.push(ch[0][i]),add(0,ch[0][i]);}
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=0;i<26;++i){;
            if(ch[u][i])f[ch[u][i]]=ch[f[u]][i],add(f[ch[u][i]],ch[u][i]),q.push(ch[u][i]);
            else ch[u][i]=ch[f[u]][i];
        }
    }
}
inline void upd(int x,int y){while(x<=dfnn)tr[x]+=y,x+=x&-x;}
inline int query(int x){int ans=0;while(x)ans+=tr[x],x-=x&-x;return ans;}
inline void ins(int id){
    int len=strlen(s);int now=0;
    for(int i=0;i<len;++i){
        if(!ch[now][s[i]-'a'])ch[now][s[i]-'a']=++tott;
        now=ch[now][s[i]-'a'];
    }
    tag[id]=now;
}
void dfs(int u){
    size[u]=1;//cout<<u<<" ";
    for(int i=head[u];i;i=e[i].n){
        int v=e[i].to;deep[v]=deep[u]+1;fa[v]=u;
        dfs(v);
        size[u]+=size[v];
        if(size[v]>size[son[u]]||!son[u])son[u]=v;
    }
}
void dfs2(int u){
    if(!top[u])top[u]=u;dfn[u]=++dfnn;fan[dfnn]=u;
    if(son[u])top[son[u]]=top[u],dfs2(son[u]);
    for(int i=head[u];i;i=e[i].n){
        int v=e[i].to;
        if(v!=son[u])dfs2(v); 
    }
}
int getlca(int u,int v){
    while(top[u]!=top[v]){
        if(deep[top[u]]<deep[top[v]])swap(u,v);
        u=fa[top[u]]; 
    }
    return min(dfn[u],dfn[v]);
}
int main(){
    n=rd();
    for(int i=1;i<=n;++i){scanf("%s",s);ins(i);}
    get_fail();
    dfs(0);dfs2(0);
    int q=rd(); 
    while(q--){
        int opt=rd();
        if(opt==1){
            scanf("%s",s);int len=strlen(s),now=0;topp=0;
            for(int i=0;i<len;++i){
                now=ch[now][s[i]-'a'];
                zh[++topp]=dfn[now];
            } 
            sort(zh+1,zh+topp+1);
            for(int i=1;i<=topp;++i){
                upd(zh[i],1);
                if(i!=1)upd(getlca(fan[zh[i-1]],fan[zh[i]]),-1);
            }
        }
        else{
            int x=tag[rd()];
            printf("%d
",query(dfn[x]+size[x]-1)-query(dfn[x]-1));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ZH-comld/p/10371731.html