Bzoj3926 [Zjoi2015]诸神眷顾的幻想乡

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 1241  Solved: 729

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%的数据,除某两块空地与三个空地相邻外,其他空地都分别至多与两个空地相邻

 

字符串 广义后缀自动机

叶子结点不超过20个,事情就好办了。

可以分别从这些叶子结点开始DFS,建20棵trie树,整个树的任何一个子串,都是某个Trie上从一个点到它的一个子孙的路径。把这些trie建到同一个后缀自动机上,统计答案。

 

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<vector>
 8 using namespace std;
 9 const int mxn=100010;
10 int read(){
11     int x=0,f=1;char ch=getchar();
12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
14     return x*f;
15 }
16 struct edge{
17     int v,nxt;
18 }e[mxn<<1];
19 int hd[mxn],mct=0;
20 void add_edge(int u,int v){
21     e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return;
22 }
23 struct SAM{
24     int t[mxn*35][10];
25     int fa[mxn*35],l[mxn*35];
26     int S,cnt,last;
27     void init(){S=cnt=last=1;return;}
28     int add(int c,int p){
29         int np=++cnt;l[np]=l[p]+1;
30         for(;p && !t[p][c];p=fa[p])t[p][c]=np;
31         if(!p){fa[np]=S;}
32         else{
33             int q=t[p][c];
34             if(l[q]==l[p]+1)fa[np]=q;
35             else{
36                 int nq=++cnt;l[nq]=l[p]+1;
37                 memcpy(t[nq],t[q],sizeof t[q]);
38                 fa[nq]=fa[q];
39                 fa[q]=fa[np]=nq;
40                 for(;p && t[p][c]==q;p=fa[p])t[p][c]=nq;
41             }
42         }
43         return np;
44     }
45     void solve(){
46         long long res=0;
47         for(register int i=1;i<=cnt;i++){
48             res+=l[i]-l[fa[i]];
49         }
50         printf("%lld\n",res);
51         return;
52     }
53 }sa;
54 int n,c;
55 int co[mxn],in[mxn];
56 void DFS(int u,int fa,int id){
57     int d=sa.add(co[u],id);
58     for(int i=hd[u];i;i=e[i].nxt){
59         if(e[i].v==fa)continue;
60         DFS(e[i].v,u,d);
61     }
62     return;
63 }
64 int main(){
65     int i,j,u,v;
66     n=read();c=read();
67     for(i=1;i<=n;i++)co[i]=read();
68     for(i=1;i<n;i++){
69         u=read();v=read();
70         add_edge(u,v);
71         add_edge(v,u);
72         ++in[u];++in[v];
73     }
74     sa.init();
75     for(i=1;i<=n;i++) if(in[i]==1) DFS(i,0,1);
76     sa.solve();
77     return 0;
78 }

 

posted @ 2017-03-10 20:16  SilverNebula  阅读(163)  评论(0编辑  收藏  举报
AmazingCounters.com