您的位置:首页 > 其它

[BZOJ3926][Zjoi2015]诸神眷顾的幻想乡(广义后缀自动机)

2017-03-30 11:34 459 查看

题目描述

传送门

题解

只与一个空地相邻的空地就是指叶子节点,刚开始理解错了

对于每一个叶子节点以它为根然后对这棵树建立广义后缀自动机

然后对于后缀自动机上的每一个点,以这个点为结尾的不相同的字符串其实就是step(i)-step(pre(i))个,也就是合法的区间长度

因为同一个字符串不会跑到不同的点上去啊…

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 100005

int n,c,a
,d
,loc
,root,sz,np,q,nq;
int tot,point
,nxt[N*2],v[N*2];
int ch[N*40][11],pre[N*40],step[N*40];
long long ans;

void extend(int p,int i)
{
int x=a[i];
np=++sz;loc[i]=np;
step[np]=step[p]+1;
while (p&&!ch[p][x])
{
ch[p][x]=np;
p=pre[p];
}
if (!p) pre[np]=root;
else
{
q=ch[p][x];
if (step[q]==step[p]+1) pre[np]=q;
else
{
nq=++sz;
step[nq]=step[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
pre[nq]=pre[q];
while (ch[p][x]==q)
{
ch[p][x]=nq;
p=pre[p];
}
pre[np]=pre[q]=nq;
}
}
}
void add(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
}
void dfs(int x,int fa)
{
extend(loc[fa],x);
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
dfs(v[i],x);
}
int main()
{
scanf("%d%d",&n,&c);
for (int i=1;i<=n;++i) scanf("%d",&a[i]);
for (int i=1;i<n;++i)
{
int x,y;scanf("%d%d",&x,&y);
add(x,y),add(y,x);
++d[x],++d[y];
}
root=++sz;loc[0]=root;
for (int i=1;i<=n;++i)
if (d[i]==1) dfs(i,0);
for (int i=1;i<=sz;++i) ans+=(long long)step[i]-step[pre[i]];
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: