BZOJ 3879: SvT [虚树 后缀树]

传送门

题意:

多次询问,给出一些后缀,求两两之间$LCP$之和


哈哈哈哈哈哈哈竟然$1A$了,刚才还在想如果写不好这道题下节数学就不上了,看来是上天让我上数学课啊

$Suffix\ Virtual\ Tree$

没有多次询问就是那道差异了

多次询问总次数$O(n)$,建出后缀树每次建虚树就行了

然后询问给出的是后缀,用一个$pos$映射到后缀树上的点

然后$Right$集合要在$DP$的时候递推

貌似还有后缀数组的做法跑的好快

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=1e6+,INF=1e9;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
} int n,Q;
char s[N];
struct State{
int ch[],par,val;
}t[N];
int sz=,root=,last=;
int pos[N];
void extend(int c){
int p=last,np=++sz;
t[np].val=t[p].val+;
for(;p&&!t[p].ch[c];p=t[p].par) t[p].ch[c]=np;
if(!p) t[np].par=root;
else{
int q=t[p].ch[c];
if(t[q].val==t[p].val+) t[np].par=q;
else{
int nq=++sz;
t[nq]=t[q];t[nq].val=t[p].val+;
t[q].par=t[np].par=nq;
for(;p&&t[p].ch[c]==q;p=t[p].par) t[p].ch[c]=nq;
}
}
last=np;
} struct Edge{
int v,ne;
}e[N];
int cnt,h[N];
inline void ins(int u,int v){
cnt++;
e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
}
int dfn[N],dfc,fa[N][],deep[N];
void dfs(int u){
dfn[u]=++dfc;
for(int i=;(<<i)<=deep[u];i++)
fa[u][i]=fa[ fa[u][i-] ][i-];
for(int i=h[u];i;i=e[i].ne)
if(e[i].v!=fa[u][]){
fa[e[i].v][]=u;
deep[e[i].v]=deep[u]+;
dfs(e[i].v);
}
}
inline int lca(int x,int y){
if(deep[x]<deep[y]) swap(x,y);
int bin=deep[x]-deep[y];
for(int i=;i>=;i--)
if((<<i)&bin) x=fa[x][i];
for(int i=;i>=;i--)
if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return x==y ? x : fa[x][];
} inline bool cmp(int x,int y){return dfn[x]<dfn[y];}
int st[N],key[N],a[N];
int d[N];
ll ans;
void dp(int u){
d[u]=key[u] ? : ;
for(int i=h[u];i;i=e[i].ne){
dp(e[i].v);
ans+=(ll)d[u]*d[e[i].v]*t[u].val;
d[u]+=d[e[i].v];
}
h[u]=;
}
void VirTree(){
cnt=;
int n=read();
for(int i=;i<=n;i++) a[i]=pos[read()];
sort(a+,a++n);
int p=;a[++p]=a[];
for(int i=;i<=n;i++) if(a[i]!=a[i-]) a[++p]=a[i];
n=p;
sort(a+,a++n,cmp);
for(int i=;i<=n;i++) key[a[i]]=; int top=;
for(int i=;i<=n;i++){
if(!top) {st[++top]=a[i];continue;}
int x=a[i],f=lca(x,st[top]);
while(dfn[f]<dfn[st[top]]){
if(dfn[f]>=dfn[st[top-]]){
ins(f,st[top--]);
if(f!=st[top]) st[++top]=f;
break;
}else ins(st[top-],st[top]),top--;
}
st[++top]=x;
}
while(top>) ins(st[top-],st[top]),top--; ans=;
dp(st[]);
printf("%lld\n",ans);
for(int i=;i<=n;i++) key[a[i]]=;
} int main(){
freopen("in","r",stdin);
n=read();Q=read();
scanf("%s",s+);
reverse(s+,s++n);
for(int i=;i<=n;i++) extend(s[i]-'a'),pos[n-i+]=last;
for(int i=;i<=sz;i++) ins(t[i].par,i);
dfs(root);
memset(h,,sizeof(h));
while(Q--) VirTree();
}
上一篇:setTimeout 和 setInteval 的区别。


下一篇:转::before和::after伪元素的用法