【bzoj3926】诸神眷顾的幻想乡

  • 本文为博主原创,未经许可不得转载

广义后缀自动机真是exciting

只需要从叶子节点遍历出20颗trie树,然后把这些trie树建成SAM即可

至于把trie树建成SAM,只需要每次从root插入就行了

我也不知道为什么这么做是对的,回头要啃一下2015集训队论文

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
#include<bits/stdc++.h>
#define MAXN 4000010
#define FILE "read"
using namespace std;
typedef long long ll;
struct node{int y,next;}e[MAXN<<1];
int n,m,len,cnt(1),Link[MAXN],v[MAXN],d[MAXN],mx[MAXN],par[MAXN],tr[MAXN][15];
ll ans;
inline int read(){
int x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
void insert(int x,int y){e[++len].next=Link[x];Link[x]=len;e[len].y=y;d[y]++;}
int extend(int p,int x){
int np=++cnt; mx[np]=mx[p]+1;
while(p&&!tr[p][x]) tr[p][x]=np,p=par[p];
if(!p) par[np]=1;
else{
int q=tr[p][x];
if(mx[q]==mx[p]+1) par[np]=q;
else{
int nq=++cnt; mx[nq]=mx[p]+1;
memcpy(tr[nq],tr[q],sizeof(tr[q]));
par[nq]=par[q]; par[q]=par[np]=nq;
while(tr[p][x]==q&&p) tr[p][x]=nq,p=par[p];
}
}
return np;
}
void dfs(int x,int fa,int last){
int now=extend(last,v[x]);
for(int i=Link[x];i;i=e[i].next)
if(e[i].y!=fa) dfs(e[i].y,x,now);
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
n=read(); m=read();
for(int i=1;i<=n;++i) v[i]=read();
for(int i=1;i<n;++i){
int x=read(),y=read();
insert(x,y); insert(y,x);
}
for(int i=1;i<=n;++i)if(d[i]==1)dfs(i,0,1);
for(int i=1;i<=cnt;++i) ans+=mx[i]-mx[par[i]];
printf("%lld\n",ans);
return 0;
}
文章目录
,