日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日。

粉丝们非常热情,自发组织表演了一系列节目给幽香看。幽香当然也非常高兴啦。 
这时幽香发现了一件非常有趣的事情,太阳花田有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%的数据,除某两块空地与三个空地相邻外,其他空地都分别至多与两个空地相邻

Source

[Submit][Status][Discuss]

SAM模板题,只要看出来字符串模型就行。注意要从叶子开始。

UPD:哦这好像是个广义后缀自动机,没什么区别吧。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef long long ll;
using namespace std; const int N=,M=;
ll ans;
int tot=,n,c,u,v,cnt,ind[N],a[N],son[M][],fa[M],mx[M],nxt[N],h[N],to[N];
void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } int extend(int p,int c){
int np=++tot; mx[np]=mx[p]+;
while (!son[p][c] && p) son[p][c]=np,p=fa[p];
if (!p) fa[np]=;
else{
int q=son[p][c];
if (mx[q]==mx[p]+) fa[np]=q;
else{
int nq=++tot; mx[nq]=mx[p]+;
memcpy(son[nq],son[q],sizeof(son[q]));
fa[nq]=fa[q]; fa[np]=fa[q]=nq;
while (p && son[p][c]==q) son[p][c]=nq,p=fa[p];
}
}
return np;
} void solve(){ rep(i,,tot) ans+=mx[i]-mx[fa[i]]; } void dfs(int x,int fa,int p){
int t=extend(p,a[x]);
for (int i=h[x]; i; i=nxt[i]) if (to[i]!=fa) dfs(to[i],x,t);
} int main(){
freopen("bzoj3926.in","r",stdin);
freopen("bzoj3926.out","w",stdout);
scanf("%d%d",&n,&c);
rep(i,,n) scanf("%d",&a[i]);
rep(i,,n-) scanf("%d%d",&u,&v),add(u,v),add(v,u),ind[u]++,ind[v]++;
rep(i,,n) if (ind[i]==) dfs(i,,);
solve(); printf("%lld\n",ans);
return ;
}

最新文章

  1. 06.GitHub实战系列~6.过滤器过滤掉的文件如何上传
  2. Azure PowerShell (1) PowerShell入门
  3. SharePoint 2013 母版页取消和HTML页关联
  4. day 2远程连接Linux系统管理
  5. PostgreSQL中的时间操作总结
  6. java web 学习 --第四天(Java三级考试)
  7. php日期处理 -- 获取本周和上周的开始日期和结束日期(备忘)
  8. [Java]eclipse的使用
  9. duilib底层机制剖析:窗体类与窗体句柄的关联
  10. Codeforces Round #321 div2
  11. EXCEL : We can&#39;t do that to a merged cell.
  12. 快速批量导入庞大数据到SQL SERVER数据库(ADO.NET)
  13. PC和ARM平台编译Qt的命令
  14. windows server 2012显示桌面图标
  15. C#枚举数和迭代器
  16. MySQL主从复制与主主复制
  17. Mongodb相关 (Shell命令 / mongoose)
  18. unable to load http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl
  19. Velocity Obstacle
  20. 二维码生成:使用 JavaScript 库QRCode.js生成二维码

热门文章

  1. 【CodeForces】915 F. Imbalance Value of a Tree 并查集
  2. Django之组合搜索组件(二)--另附simple_tag的创建使用方法
  3. docker 加速
  4. oracle数据库只查询前n条
  5. linux 查看内存和cpu占用比较多的进程
  6. perl6正则 4: before / after 代码断言: &lt;?{}&gt; / &lt;!{}&gt;
  7. c++环境配置 Eclipse+mingw-get-setup
  8. Codeforces 813B The Golden Age(数学+枚举)
  9. linux中的vim 编辑一行内容,如何使光标快速移动到行首和行尾以及行中间某处啊?
  10. 关于node.js的模块查找顺序(require.resolve())