1. 程式人生 > >[bzoj3172][Tjoi2013]單詞——AC自動機

[bzoj3172][Tjoi2013]單詞——AC自動機

一個 dig debug 自動機 getc 前綴 rst cto space

題目大意:

某人讀論文,一篇論文是由許多單詞組成。但他發現一個單詞會在論文中出現很多次,現在想知道每個單詞分別在論文中出現多少次。

思路:

第i個單詞在整個文章中出現了多少次即i串的結尾可以被多少個串的節點給跳到。
於是吧fail看成每個節點唯一的父親,每個節點的權值為有多少個單詞的前綴經過了它,然後直接統計子樹內的權值和即可。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;

using namespace std;

void File(){
    freopen("bzoj3172.in","r",stdin);
    freopen("bzoj3172.out","w",stdout);
}

template<typename T>void read(T &_){
    _=0; T f=1; char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    _*=f;
}

const int maxn=1e6+10;
int n,cnt_rank,ans[maxn],weight[maxn];
int ch[maxn][26],num[maxn],fail[maxn],cnt=1;
vector<int>rank[maxn];

void insert(char *s){
    int len=strlen(s+1),u=1,c;
    REP(i,1,len){
        c=s[i]-'a';
        if(!ch[u][c])ch[u][c]=++cnt;
        u=ch[u][c];
        ++weight[u];
    }
    ++num[u];
    rank[u].pb(++cnt_rank);
}

void build_fail(){
    int h=1,t=0,q[maxn];
    fail[1]=1;
    REP(i,0,25){
        int v=ch[1][i];
        if(v)q[++t]=v;
        if(v)fail[v]=1;
        else ch[1][i]=1;
    }
    while(h<=t){
        int u=q[h++];
        REP(i,0,25){
            int v=ch[u][i];
            if(v)q[++t]=v;
            if(v)fail[v]=max(ch[fail[u]][i],1);
            else ch[u][i]=max(ch[fail[u]][i],1);
        }
    }
}

int beg[maxn],to[maxn],las[maxn],cnte=1;
int sz[maxn];

void add(int u,int v){
    las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v;
}

void dfs(int u){
    sz[u]=weight[u];
    for(int i=beg[u];i;i=las[i]){
        dfs(to[i]);
        sz[u]+=sz[to[i]];
    }
    REP(i,0,rank[u].size()-1)ans[rank[u][i]]=sz[u];
}

int main(){
    File();

    char s[maxn];

    read(n);
    REP(i,1,n){
        scanf("%s",s+1);
        //printf("%s\n",s+1);
        insert(s);
    }

    build_fail();
    REP(i,2,cnt)add(fail[i],i);

    dfs(1);

    REP(i,1,n)printf("%d\n",ans[i]);

    return 0;
}

[bzoj3172][Tjoi2013]單詞——AC自動機