您的位置:首页 > 其它

【bzoj3926】[Zjoi2015]诸神眷顾的幻想乡 后缀自动机

2016-06-29 21:37 323 查看
注意到叶子节点只有20个,从每个叶子节点开始dfs,在得到的trie树上建后缀自动机

比较神奇的是,我们不用考虑那么多奇怪的问题,每个节点只需要从它trie树上的父亲节点开始建后缀自动机,就是对的

讲道理,我连增量法都没理解透,更何况树上的呢,反正直接建就对了

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 100010

using namespace std;

int head[maxn],to[2*maxn],next[2*maxn],d[maxn],w[maxn];
int fa[2*20*maxn],ch[2*20*maxn][26],mx[2*20*maxn];
int n,m,num,tot=1,c;
long long ans;

void addedge(int x,int y) {num++;to[num]=y;next[num]=head[x];head[x]=num;}

int insert(int p,int x)
{
int np=++tot;
mx[np]=mx[p]+1;
while (p && !ch[p][x]) ch[p][x]=np,p=fa[p];
if (!p) fa[np]=1;
else
{
int q=ch[p][x];
if (mx[q]==mx[p]+1) fa[np]=q;
else
{
int nq=++tot;mx[nq]=mx[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];
fa[np]=fa[q]=nq;
while (p && ch[p][x]==q) ch[p][x]=nq,p=fa[p];
}
}
return np;
}

void dfs(int x,int fa,int p)
{
int now=insert(p,w[x]);
for (int p=head[x];p;p=next[p])
if (to[p]!=fa) dfs(to[p],x,now);
}

int main()
{
scanf("%d%d",&n,&c);
for (int i=1;i<=n;i++) scanf("%d",&w[i]);
for (int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);addedge(y,x);
d[x]++;d[y]++;
}
for (int i=1;i<=n;i++) if (d[i]==1) dfs(i,0,1);
for (int i=1;i<=tot;i++) ans+=mx[i]-mx[fa[i]];
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: