Jzoj5665 奥立卡的诗
终于又遇到SAM的题了好好玩,而且就这道题让我弄清楚了广义SAM和Trie上SAM的区别
其实两者是没有多少区别的,不过Trie上SAM可以更快
关于Trie上SAM,是用bfs的方法来构建的,相比起广义SAM用dfs建少了一个深度之和的部分
但是如果原题给的就是Trie那么就只能用bfs了,因为dfs会被卡成O(n^2) (考虑一个扫把)
回到本题,简化一下式子发现这道题求的是不同子串的出现次数的平方和
我们建出整个诗的广义SAM,对于一次询问,
我们将一个串每个前缀对应的节点size都加一,树链剖分来维护所有节点的权值平方和
让后就愉快的过了
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 600010
#define LL long long
#define mid (l+r>>1)
#define ls l,mid,x<<1
#define rs mid+1,r,x<<1|1
using namespace std;
char C[N]; LL ans=0;
struct edge{ int v,nt; } G[N<<1];
int n,m,cnt,clk,h[N],f[N],d[N],sz[N];
int top[N],w[N],l[N],son[N],dx[N]; LL s2[N<<2],s[N<<2],t[N<<2],c[N<<2];
inline void ps(int x){
s[x]=s[x<<1]+s[x<<1|1];
s2[x]=s2[x<<1]+s2[x<<1|1];
}
inline void adj(int x,int y){
G[++cnt]=(edge){y,h[x]}; h[x]=cnt;
G[++cnt]=(edge){x,h[y]}; h[y]=cnt;
}
inline void dfs(int x,int p){
f[x]=p; d[x]=d[p]+1; sz[x]=1;
for(int v,i=h[x];i;i=G[i].nt)
if(!d[v=G[i].v]){
dfs(v,x);
sz[x]+=sz[v];
if(sz[v]>sz[son[x]]) son[x]=v;
}
}
inline void dgs(int x,int p){
w[++clk]=x; l[x]=clk; top[x]=p;
if(son[x]) dgs(son[x],p);
for(int v,i=h[x];i;i=G[i].nt)
if(!top[v=G[i].v]) dgs(v,v);
}
inline void build(int l,int r,int x){
if(l==r){ c[x]=dx[w[l]]; return; }
build(ls);
build(rs);
c[x]=c[x<<1]+c[x<<1|1];
}
inline void pd(int x){
if(t[x]){
t[x<<1]+=t[x];
t[x<<1|1]+=t[x];
s2[x<<1]+=t[x]*t[x]*c[x<<1]+2*t[x]*s[x<<1];
s2[x<<1|1]+=t[x]*t[x]*c[x<<1|1]+2*t[x]*s[x<<1|1];
s[x<<1]+=c[x<<1]*t[x];
s[x<<1|1]+=c[x<<1|1]*t[x];
t[x]=0;
}
}
inline void add(int l,int r,int x,int L,int R){
if(L<=l && r<=R){
s2[x]+=c[x]+2*s[x];
s[x]+=c[x]; t[x]++; return;
}
pd(x);
if(L<=mid) add(ls,L,R);
if(mid<R) add(rs,L,R);
ps(x);
}
inline void gLca(int x){
for(;x;x=f[top[x]])
add(1,n,1,l[top[x]],l[x]);
}
struct SAM{
int s[N][26],mx[N],f[N],cnt,lst;
SAM(){ cnt=lst=1; }
inline int extend(int c){
int p=lst,np=lst=++cnt,q,nq;
mx[np]=mx[p]+1;
for(;p&&!s[p][c];p=f[p]) s[p][c]=np;
if(!p) return f[np]=1;
q=s[p][c];
if(mx[q]==mx[p]+1) f[np]=q;
else{
nq=++cnt;
mx[nq]=mx[p]+1;
f[nq]=f[q]; f[q]=f[np]=nq;
memcpy(s[nq],s[q],26<<2);
for(;p&&s[p][c]==q;p=f[p]) s[p][c]=nq;
}
}
inline void Ex_extend(int c){
int p=lst,q=s[p][c],nq;
if(q){
if(mx[q]==mx[p]+1){ lst=q; }
else{
lst=nq=++cnt;
mx[nq]=mx[p]+1;
f[nq]=f[q]; f[q]=nq;
memcpy(s[nq],s[q],26<<2);
for(;p&&s[p][c]==q;p=f[p]) s[p][c]=nq;
}
} else extend(c);
}
inline void BT(){
for(int i=2;i<=cnt;++i){
adj(f[i],i);
dx[i]=mx[i]-mx[f[i]];
}
}
} S;
int main(){
freopen("poem.in","r",stdin);
freopen("poem.out","w",stdout);
scanf("%d",&n);
for(int j=0;n--;++j){
scanf("%s",C+j); S.lst=1;
for(;C[j];++j) S.Ex_extend(C[j]-'a');
}
n=S.cnt; S.BT(); dfs(1,0); dgs(1,1); build(1,n,1);
for(int x=1,j=0;C[j];++j){
x=1;
while(C[j]){
x=S.s[x][C[j]-'a'];
gLca(x); ++j;
}
printf("%lld\n",s2[1]);
}
}