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 3
0 2 1 2 1 0 0
1 2
3 4
3 5
4 6
5 7
2 5

Sample Output

30

HINT

对于所有数据,1<=n<=100000, 1<=c<=10。

对于15%的数据,n<=2000。
另有5%的数据,所有空地都至多与两个空地相邻。
另有5%的数据,除一块空地与三个空地相邻外,其他空地都分别至多与两个空地相邻。
另有5%的数据,除某两块空地与三个空地相邻外,其他空地都分别至多与两个空地相邻

Solution

广义$SAM$,也就是给一个$Trie$建$SAM$。具体操作很简单,就是$DFS$一下$Trie$树,每次将一个字符插入$SAM$的时候,将$SAM$的$last$记为这个字符在$Trie$树上的父亲的$np$就可以了。

由于一种字符串只能做出一次贡献,所以答案为$ans=\sum step[i]-step[fa[i]]$

Code

 #include<iostream>
#include<cstring>
#include<cstdio>
#define N (2000009)
#define M (100009)
#define LL long long
using namespace std; struct Edge{int to,next;}edge[M<<];
int head[M],num_edge;
int n,m,u,v,a[M],Ind[M]; void add(int u,int v)
{
edge[++num_edge].to=v;
edge[num_edge].next=head[u];
head[u]=num_edge;
} struct SAM
{
int son[N][],fa[N],step[N],wt[N],od[N];
int p,q,np,nq,cnt;
SAM(){cnt=;} int Insert(int last,int x)
{
p=last; np=++cnt; step[np]=step[p]+;
while (!son[p][x] && p) son[p][x]=np, p=fa[p];
if (!p) fa[np]=;
else
{
q=son[p][x];
if (step[p]+==step[q]) fa[np]=q;
else
{
nq=++cnt; step[nq]=step[p]+;
memcpy(son[nq],son[q],sizeof(son[q]));
fa[nq]=fa[q]; fa[q]=fa[np]=nq;
while (son[p][x]==q) son[p][x]=nq, p=fa[p];
}
}
return np;
}
void Calc()
{
LL ans=;
for (int i=; i<=cnt; ++i)
ans+=(LL)(step[i]-step[fa[i]]);
printf("%lld\n",ans);
}
}SAM; void DFS(int x,int fa,int pre)
{
int tmp=SAM.Insert(pre,a[x]);
for (int i=head[x]; i; i=edge[i].next)
if (edge[i].to!=fa) DFS(edge[i].to,x,tmp);
} int main()
{
scanf("%d%d",&n,&m);
for (int i=; i<=n; ++i)
scanf("%d",&a[i]);
for (int i=; i<=n-; ++i)
{
scanf("%d%d",&u,&v);
add(u,v); add(v,u);
Ind[u]++; Ind[v]++;
}
for (int i=; i<=n; ++i)
if (Ind[i]==) DFS(i,-,);
SAM.Calc();
}

最新文章

  1. [Python]记录详细调用堆栈的日志
  2. iOS5.0以上使用新浪微博开放平台OAuth 续(及解决登录无效问题)
  3. jmeter-HTTP COOKIE Manager
  4. Linux的vim三种模式及命令
  5. UVA 10791 - Minimum Sum LCM(坑)
  6. github仓库的克隆、修改、上传方法(图)
  7. Mysql基础2
  8. Sql 行转列问题总结
  9. 12个有趣的C语言面试题
  10. Cookie和Session(session过程和设置进程外session)
  11. WinExec函数,启动其他应用程序
  12. 2014年百度之星程序设计大赛 - 资格赛 第三题 Xor Sum
  13. 计算机学院大学生程序设计竞赛(2015’12) 1009 The Magic Tower
  14. AI之微信跳一跳
  15. keras实现简单性别识别(二分类问题)
  16. L2-010 排座位 (并查集)
  17. ASP.NET Core如何使用WSFederation身份认证集成ADFS
  18. 2018秋寒假作业6- -PTA编程总结3
  19. Class PropertyPlaceholderHelper的使用
  20. Spring Boot 2 实践记录之 组合注解原理

热门文章

  1. 个人开源项目之异步Http线程池框架
  2. [转] 常用的sql server规范
  3. [javaSE] IO流(FIle对象递归文件列表)
  4. Java Swing实战(四)按钮组件JButton及其事件监听
  5. 中南月赛F ZZY and his little friends
  6. HDU2048 神,上帝以及老天爷 错排
  7. 并发模型之Future设计模式
  8. 前端之body标签中相关标签(二)
  9. java中的&gt;&gt;&gt;和&gt;&gt;&gt;=
  10. Drupal7安装注意事项