bzoj 3926 诸神眷顾的幻想乡

广义 $SAM$ .

  • 广义 $SAM$ ,就是在 $Trie$ 树上建 $SAM$ .注意到树上的每个串都可以看成以某个叶子节点为根的 $Trie$ 树上的一条路径.
  • 而叶子节点数 $\leq 20$ ,所以可以以每个叶子节点为根建 $Trie$ 树,建的时候需要注意插入一个点时,将 $lst$ 置为其父亲在 $SAM​$ 上对应的节点.
  • 注意判重,即处理插入一个字符时, $lst$ 对应的转移边已经有点的情况.建好后就是问有多少个不同子串,每个点的贡献都是 $Max-Min+1$ .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int MAXN=1e7+10;
const int Siz=10;
int n;
struct SuffixAutoMation
{
int idx,lst;
SuffixAutoMation(){lst=idx=1;}
int fa[MAXN],ch[MAXN][Siz];
int len[MAXN];
int Extend(int p,int c)
{
if(ch[p][c])
{
int q=ch[p][c];
if(len[q]==len[p]+1)
lst=q;
else
{
int nq=++idx;
lst=nq;
len[nq]=len[p]+1;
fa[nq]=fa[q];
fa[q]=nq;
memcpy(ch[nq],ch[q],sizeof ch[q]);
while(p && ch[p][c]==q)
ch[p][c]=nq,p=fa[p];
}
}
else
{
int np=++idx;
lst=np;
len[np]=len[p]+1;
while(p && ch[p][c]==0)
ch[p][c]=np,p=fa[p];
if(p==0)
fa[np]=1;
else
{
int q=ch[p][c];
if(len[q]==len[p]+1)
fa[np]=q;
else
{
int nq=++idx;
len[nq]=len[p]+1;
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
memcpy(ch[nq],ch[q],sizeof ch[q]);
while(p && ch[p][c]==q)
ch[p][c]=nq,p=fa[p];
}
}
}
return lst;
}
void solve()
{
ll ans=0;
for(int i=2;i<=idx;++i)
ans+=len[i]-len[fa[i]];
cout<<ans<<endl;
}
}SAM;
int ecnt=0,head[MAXN],to[MAXN],nx[MAXN],deg[MAXN];
void addedge(int u,int v)
{
++deg[u];
++ecnt;
to[ecnt]=v;
nx[ecnt]=head[u];
head[u]=ecnt;
}
int col[MAXN];
void dfs(int u,int fa,int lst)
{
int newlst=SAM.Extend(lst,col[u]);
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(v==fa)
continue;
dfs(v,u,newlst);
}
}
int main()
{
n=read();
int c=read();
for(int i=1;i<=n;++i)
col[i]=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read();
addedge(u,v);
addedge(v,u);
}
for(int i=1;i<=n;++i)
if(deg[i]==1)
dfs(i,0,1);
SAM.solve();
return 0;
}