P3346 [ZJOI2015]诸神眷顾的幻想乡 广义SAM
题意:
分析:
题目相当于让我们求树上有多少本质不同的路径,但是我们发现直接建 \(trie\) 树的话 \(M\) 字型的路径,没有办法表示出来
然后我们发现题目有这么一句话 由于太阳花田的结构比较特殊,只与一个空地相邻的空地数量不超过 20 个
,这句话提醒了我们换个角度思考问题,我们查看题解可以发现,每一个 \(M\) 型的路径必定可以表示为以一个叶子结点为根的 \(trie\) 树上一条一条直的路径,所以直接以叶子为根建出广义 SAM,求出本质不同的子串
代码:
#include<bits/stdc++.h>
using namespace std;
namespace zzc
{
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-48;ch=getchar();}
return x*f;
}
const int maxn = 2e6+5;
int n,cnt;
int c[maxn],head[maxn],deg[maxn];
struct edge
{
int to,nxt;
}e[maxn<<1];
void add(int u,int v)
{
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
deg[v]++;
}
struct trie
{
int tot;
int c[maxn],trans[maxn][15],link[maxn];
trie(){tot=1;}
int insert(int f,int x)
{
if(!trans[f][x]) trans[f][x]=++tot,link[tot]=f,c[tot]=x;
return trans[f][x];
}
}tr;
struct suffix_automaton
{
int tot;
int trans[maxn][15],link[maxn],id[maxn],len[maxn];
queue<int> q;
suffix_automaton(){tot=1;}
int insert(int x,int lst)
{
int cur=++tot,tmp=lst;
len[cur]=len[tmp]+1;
for(;tmp&&!trans[tmp][x];tmp=link[tmp]) trans[tmp][x]=cur;
if(!tmp)
{
link[cur]=1;
}
else
{
int q=trans[tmp][x];
if(len[tmp]+1==len[q])
{
link[cur]=q;
}
else
{
int clone=++tot;
len[clone]=len[tmp]+1;
for(int i=0;i<=10;i++) trans[clone][i]=trans[q][i];
link[clone]=link[q];
link[cur]=link[q]=clone;
for(;tmp&&trans[tmp][x]==q;tmp=link[tmp]) trans[tmp][x]=clone;
}
}
return cur;
}
void build()
{
for(int i=0;i<=10;i++) if(tr.trans[1][i]) q.push(tr.trans[1][i]);
id[1]=1;
while(!q.empty())
{
int u=q.front();q.pop();
id[u]=insert(tr.c[u],id[tr.link[u]]);
for(int i=0;i<=10;i++) if(tr.trans[u][i]) q.push(tr.trans[u][i]);
}
}
void sort()
{
long long ans=0;
for(int i=2;i<=tot;i++) ans+=len[i]-len[link[i]];
printf("%lld\n",ans);
}
}sam;
void dfs(int u,int fa,int lst)
{
int tmp=tr.insert(lst,c[u]);
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].to;
if(v==fa) continue;
dfs(v,u,tmp);
}
}
void work()
{
int a,b;
n=read();a=read();
for(int i=1;i<=n;i++) c[i]=read();
for(int i=1;i<n;i++)
{
a=read();b=read();
add(a,b);add(b,a);
}
for(int i=1;i<=n;i++) if(deg[i]==1) dfs(i,0,1);
sam.build();
sam.sort();
}
}
int main()
{
zzc::work();
return 0;
}