BZOJ 3881: [Coci2015]Divljak

(忍不住吐槽一下垃圾CSDN的改版。。一點都不好看還強制改

做了一點fail樹相關題 其實好像都沒什麼好寫的。。(阿狸的打字機是衆人皆知的了
這道題還是不錯的。
我們讓S串來構建 AC自動機
建出fail樹之後

每加入一個串 就是讓走到的所有節點 在fail樹上節點到根的距離都+1
但是他是問有多少個串 所以你要讓這些樹鏈求並 這樣就不會多加了
詢問就是問子樹和,dfs序+樹狀數組即可

#include<bits/stdc++.h>
using namespace std;
const int N=2000010,M=100005;
inline int read(){
    int x=0,f=1; char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0' && ch<='9'){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();}
    return x*f;
}
int f[N][21],t[N][26],tot,n,m,d[N];
int len,fir[N],nex[N],go[N];
void ad(int x,int y){
    nex[++len]=fir[x],fir[x]=len,go[len]=y;
}
char c[N];
void ins(int &x){
    int len=strlen(c); x=0;
    for(int i=0;i<len;++i){
        int y=c[i]-'a';
        if(!t[x][y])t[x][y]=++tot;
        x=t[x][y];
    }
}
int q[N],he,ta;
void bulid(){
    he=0,ta=0; d[0]=1;
    while(he<=ta){
        int x=q[he++];
        for(int i=0;i<26;++i){
            int son=t[x][i],F=f[x][0];
            if(son)q[++ta]=son,f[son][0]=x==0?0:t[F][i],d[son]=d[f[son][0]]+1;
            else t[x][i]=x==0?0:t[F][i];
        }
        if(x)ad(f[x][0],x);
    }
}
int lca(int x,int y){
    if(d[x]<d[y])x^=y^=x^=y; int i;
    for(i=20;~i;--i)if(d[f[x][i]]>=d[y])x=f[x][i];
    if(x==y)return x;
    for(i=20;~i;--i)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    return f[x][0];
}
int a[M],in[N],out[N],id,g[N];
void dfs(int x){
    in[x]=++id;
    for(int i=1;i<21;++i)
        if(f[x][i-1])f[x][i]=f[f[x][i-1]][i-1];
        else break;
    for(int k=fir[x];k;k=nex[k])dfs(go[k]);
    out[x]=id;
}
void add(int x,int u){for(;x<=id;x+=x&-x)g[x]+=u;}
int get(int x){int u=0;for(;x;x-=x&-x)u+=g[x];return u;}
int p[N],pl;
int Cmp(int x,int y){return in[x]<in[y];}
void Ins(){
    int len=strlen(c),x=0; p[pl=1]=0;
    for(int i=0;i<len;++i){
        x=t[x][c[i]-'a'];
        p[++pl]=x;
    }
    sort(p+1,p+1+pl,Cmp);
    pl=unique(p+1,p+1+pl)-p-1;
    add(in[p[1]],1);
    for(int i=2;i<=pl;++i){
        int l=lca(p[i],p[i-1]);
        add(in[p[i]],1);
        add(in[l],-1);
    }
}
int main(){
    int n=read(),i;
    for(i=1;i<=n;++i){
        scanf("%s",c); ins(a[i]);
    }
    bulid(); dfs(0);
    int q=read();
    while(q--){
        int u=read();
        if(u==1)
            scanf("%s",c),Ins();
        else
            u=read(),printf("%d\n",get(out[a[u]])-get(in[a[u]]-1));
    }
    return 0;
}
發佈了173 篇原創文章 · 獲贊 203 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章