版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/85553144
BZOJ传送门
洛谷传送门
解析:
裸的广义SAM,其实广义SAM在构建的时候与SAM的差别就是需要传递一个原来的父亲节点编号,其他就没什么了。
这道题要统计不同的字串个数,直接每个节点 就是这个节点对于它的父亲产生的新的子串个数,然后。。。就没有然后了。。。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc putchar
#define cs const
namespace IO{
namespace IOONLY{
cs int Rlen=1<<18|1;
char buf[Rlen],*p1,*p2;
}
inline char get_char(){
using namespace IOONLY;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int N=1000006;
vector<int> edge[N];
inline void addedge(int u,int v){
edge[u].push_back(v);
edge[v].push_back(u);
}
int n,C;
struct SAM{
int fa[N<<1],len[N<<1],son[N<<1][12];
int last,now;
SAM():last(1),now(1){}
inline int push_back(int c,int p){
int cur=++now;
len[cur]=len[p]+1;
for(;p&&!son[p][c];p=fa[p])son[p][c]=cur;
if(!p)fa[cur]=1;
else if(len[son[p][c]]==len[p]+1)fa[cur]=son[p][c];
else {
int clone=++now,q=son[p][c];
len[clone]=len[p]+1;
memcpy(son[clone],son[q],sizeof son[q]);
fa[clone]=fa[q];
fa[q]=fa[cur]=clone;
for(;p&&son[p][c]==q;p=fa[p])son[p][c]=clone;
}
return cur;
}
inline ll calc(){
re ll res=0;
for(int re i=2;i<=now;++i)res+=len[i]-len[fa[i]];
return res;
}
}sam;
int val[N];
inline void dfs(int u,int fa,int p){
int cur=sam.push_back(val[u],p);
for(int re e=0;e<edge[u].size();++e)
if(edge[u][e]^fa)dfs(edge[u][e],u,cur);
}
signed main(){
n=getint();
C=getint();
for(int re i=1;i<=n;++i)val[i]=getint();
for(int re i=1;i<n;++i)addedge(getint(),getint());
for(int re i=1;i<=n;++i)if(edge[i].size()==1)dfs(i,0,1);
printf("%lld",sam.calc());
return 0;
}