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;
}