bzoj3926(广义后缀自动机)
2016-05-03 18:48
169 查看
3926: [Zjoi2015]诸神眷顾的幻想乡
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 760 Solved: 471
[Submit][Status][Discuss]
Description
幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日。粉丝们非常热情,自发组织表演了一系列节目给幽香看。幽香当然也非常高兴啦。
这时幽香发现了一件非常有趣的事情,太阳花田有n块空地。在过去,幽香为了方便,在这n块空地之间修建了n-1条边将它们连通起来。也就是说,这n块空地形成了一个树的结构。
有n个粉丝们来到了太阳花田上。为了表达对幽香生日的祝贺,他们选择了c中颜色的衣服,每种颜色恰好可以用一个0到c-1之间的整数来表示。并且每个人都站在一个空地上,每个空地上也只有一个人。这样整个太阳花田就花花绿绿了。幽香看到了,感觉也非常开心。
粉丝们策划的一个节目是这样的,选中两个粉丝A和B(A和B可以相同),然后A所在的空地到B所在的空地的路径上的粉丝依次跳起来(包括端点),幽香就能看到一个长度为A到B之间路径上的所有粉丝的数目(包括A和B)的颜色序列。一开始大家打算让人一两个粉丝(注意:A,B和B,A是不同的,他们形成的序列刚好相反,比如红绿蓝和蓝绿红)都来一次,但是有人指出这样可能会出现一些一模一样的颜色序列,会导致审美疲劳。
于是他们想要问题,在这个树上,一共有多少可能的不同的颜色序列(子串)幽香可以看到呢?
太阳花田的结构比较特殊,只与一个空地相邻的空地数量不超过20个。
Input
第一行两个正整数n,c。表示空地数量和颜色数量。第二行有n个0到c-1之间,由空格隔开的整数,依次表示第i块空地上的粉丝的衣服颜色。(这里我们按照节点标号从小到大的顺序依次给出每块空地上粉丝的衣服颜色)。
接下来n-1行,每行两个正整数u,v,表示有一条连接空地u和空地v的边。
Output
一行,输出一个整数,表示答案。Sample Input
7 30 2 1 2 1 0 0
1 2
3 4
3 5
4 6
5 7
2 5
Sample Output
30HINT
对于所有数据,1<=n<=100000, 1<=c<=10。对于15%的数据,n<=2000。
另有5%的数据,所有空地都至多与两个空地相邻。
另有5%的数据,除一块空地与三个空地相邻外,其他空地都分别至多与两个空地相邻。
另有5%的数据,除某两块空地与三个空地相邻外,其他空地都分别至多与两个空地相邻
解题思路:广义后缀自动机,由于叶子节点比较少,对于每个叶子节点,dfs
将每个状态放入后缀自动机。然后最后在自动机上统计答案。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,c,len,cnt;
long long ans;
int to[200001],next[200001],h[200001];
int mx[4000005],fa[4000005],ch[4000005][10];
int a[100005],line[100005];
inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0'&&y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}
void ins(int x,int y)
{
++len; to[len]=y; next[len]=h[x]; h[x]=len;
}
int insert(int now,int lp)
{
int p=lp; int np=++cnt; mx[np]=mx[p]+1; int zhi=cnt;
while (p && !ch[p][a[now]]) ch[p][a[now]]=np,p=fa[p];
if (!p)fa[np]=1;else
{
int q=ch[p][a[now]];
if (mx[q]==mx[p]+1)
{
fa[np]=q;
}else
{
int nq=++cnt; mx[nq]=mx[p]+1;
fa[nq]=fa[q];
memcpy(ch[nq],ch[q],sizeof(ch[nq]));
fa[np]=fa[q]=nq;
while (ch[p][a[now]]==q) ch[p][a[now]]=nq,p=fa[p];
}
}
return zhi;
}
void dfs(int now,int fa,int po)
{
int uq=insert(now,po);
int u=h[now];
while (u!=0)
{
if (to[u]!=fa)
{
dfs(to[u],now,uq);
}
u=next[u];
}
}
int main()
{
n=read(); c=read();
for (int i=1;i<=n;++i)
a[i]=read();
for (int i=1;i<=n-1;++i)
{
int x=read(); int y=read();
ins(x,y);ins(y,x);
++line[x]; ++line[y];
}
cnt=1;
for (int i=1;i<=n;++i)
if (line[i]==1)
{
dfs(i,0,1);
}
ans=0;
for(int i=1;i<=cnt;i++)
ans+=mx[i]-mx[fa[i]];
printf("%lld",ans);
}
相关文章推荐
- Hawk-数据抓取工具
- androidstudio新建项目中在布局文件中不显示title的方法
- session保存至缓存中
- QString转LPCWSTR
- Unity3D NGUI动态生成模糊背景图
- 张飞开关电源三
- cdojR - Japan
- list集合需要深入了解的问题
- 数据库创建emp和dept练习表
- 链表-1 链表中数据的删除
- 常用正则表达式
- Python pass 语句
- 安卓自定义画布 图片,文字相结合成图片 手势放大缩小,文字颜色大小自定义
- jQuery学习之jQuery Ajax用法详解
- 【NGUI】Rpg对话框
- HDU 2222 Keywords Search
- OC面向对象—继承
- linux下php redis扩展安装
- 线程通信
- 一定要看的。深入理解Objective-C:Category