【BZOJ3926】诸神眷顾的幻想乡 【广义后缀自动机】

题意

  给定一棵树,每个结点有一个颜色,问树上有多少种子串(定义子串为两点上路径颜色的序列)。保证叶子结点<=20

分析

  我们可以发现一个结论,任意一个子串一定是以某个叶子结点为根的trie的后缀。我们有注意到,叶子节点最多只有20,那么我们可以将每个叶子结点拿出来,以它为根按照trie树的方式插到广义后缀自动机中。要统计一共有多少子串的话,这样这样建好自动机以后枚举每个状态,然后res+=st[u].len-st[st[u].link].len;

  

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 
 6 using namespace std;
 7 const int maxn=100000+100;
 8 typedef long long LL;
 9 int val[maxn];
10 int head[maxn],Next[2*maxn],to[2*maxn],deg[maxn];
11 int N,sz,C;
12 int cnt,cur;
13 struct state{
14     int len,link;
15     int next[12];
16 }st[40*maxn];
17 
18 void init(){
19     sz=0;
20     memset(head,-1,sizeof(head));
21     cnt=1;
22     cur=0;
23     st[0].link=-1;
24     st[0].len=0;
25 }
26 
27 void add_edge(int a,int b){
28     ++sz;
29     to[sz]=b;
30     Next[sz]=head[a];
31     head[a]=sz;
32 }
33 
34 int build_sam(int c,int last){
35     cur=cnt++;
36     st[cur].len=st[last].len+1;
37     int p;
38     for(p=last;p!=-1&&st[p].next[c]==0;p=st[p].link)
39         st[p].next[c]=cur;
40     if(p==-1)
41         st[cur].link=0;
42     else{
43         int q=st[p].next[c];
44         if(st[q].len==st[p].len+1)
45             st[cur].link=q;
46         else{
47             int clone=cnt++;
48             st[clone].len=st[p].len+1;
49             st[clone].link=st[q].link;
50             for(int i=0;i<C;i++)
51                 st[clone].next[i]=st[q].next[i];
52             for(;p!=-1&&st[p].next[c]==q;p=st[p].link)
53                 st[p].next[c]=clone;
54             st[cur].link=st[q].link=clone;
55         }
56     }
57     return cur;
58 }
59 
60 void dfs(int u,int fa,int las){
61     int Las=build_sam(val[u],las);
62     for(int i=head[u];i!=-1;i=Next[i]){
63         int v=to[i];
64         if(v==fa)continue;
65         dfs(v,u,Las);
66     }
67     return;
68 }
69 
70 int main(){
71     scanf("%d%d",&N,&C);
72     for(int i=1;i<=N;i++)
73         scanf("%d",&val[i]);
74     int a,b;
75     init();
76     for(int i=1;i<N;i++){
77         scanf("%d%d",&a,&b);
78         add_edge(a,b);
79         add_edge(b,a);
80         deg[a]++;deg[b]++;
81     }
82     for(int i=1;i<=N;i++){
83         if(deg[i]==1){
84             dfs(i,-1,0);
85         }
86     }
87     LL ans=0;
88     for(int i=0;i<cnt;i++){
89         int p=st[i].link;
90         if(p!=-1){
91             ans+=st[i].len-st[p].len;
92         }
93     }
94     printf("%lld\n",ans);
95 return 0;
96 }
View Code

 

posted @ 2018-11-01 20:24  蒟蒻LQL  阅读(221)  评论(0编辑  收藏  举报