bzoj3172: [Tjoi2013]单词

题目链接

bzoj3172: [Tjoi2013]单词

题解

在插入单词时对于每个点都标记一下
构建fail树
因为AC自动机节点维护前缀,fail树的关系是公共后缀,那么可以发现,答案就是该单词的fail子树总价值

代码

#include<queue> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#define LL long long
inline int read() { 
    int x = 0,f = 1;char c = getchar(); 
    while(c < '0'||c > '9')c = getchar(); 
    while(c <= '9' &&c >= '0')x = x * 10 + c - '0',c = getchar(); 
    return x * f; 
} 
#define LL long long 
int n; 
const int maxn = 1000097; 
char a[maxn];
int sz,ch[maxn][27];LL cnt[maxn]; 
struct node {
    int v,next; 
} edge[maxn << 1]; 
int num,head[maxn],loc[maxn]; 
inline void add_edge(int u,int v) { edge[++ num].v = v ;edge[num].next = head[u];head[u] = num; } 
int insert(char *t) { 
    int len = strlen(t); 
    int now = 0; 
    for(int i = 0;i < len;++ i) { 
        int  s = t[i] - 'a'; 
        if(!ch[now][s]) ch[now][s] = ++ sz; 
        now = ch[now][s]; cnt[now] ++; 
    } 
    return now; 
} 
int fail[maxn],q[maxn]; 
void get_fail(int l = 0,int r = 0 ) { 
    for(int i = 0;i <= 25;++ i)if(ch[0][i]) q[++ r] = ch[0][i]; 
    while(l < r) { 
        int u = q[++ l]; 
        for(int i = 0;i <= 25;++ i) { 
            int v = ch[u][i]; 
            if(v) fail[v] = ch[fail[u]][i],q[++ r] = v; 
            else ch[u][i] = ch[fail[u]][i]; 
        } 
    } 
} 
void dfs(int x,int fa = 0) {  
    for(int i = head[x];i;i = edge[i].next) {  
        int v = edge[i].v;  
        if(v != fa) {dfs(v,x),cnt[x] += cnt[v];}   
    }   
}  
int main() { 
    n = read();  
    for(int i = 1;i <= n;++ i) {  
        scanf("%s",a);  
        loc[i] = insert(a);  
    }  
    get_fail();  
    for(int i = 1;i <= sz;++ i) { 
        add_edge(fail[i],i); 
    } 
    dfs(0); 
    for(int i = 1;i <= n;++ i) { 
        printf("%d\n",cnt[loc[i]]); 
    } 
    return 0;
}
posted @ 2018-07-05 19:55  zzzzx  阅读(72)  评论(0编辑  收藏  举报