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+5,INF=1e9; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n,Q; char s[N]; struct State{ int ch[26],par,val; }t[N]; int sz=1,root=1,last=1; int pos[N]; void extend(int c){ int p=last,np=++sz; t[np].val=t[p].val+1; 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+1) t[np].par=q; else{ int nq=++sz; t[nq]=t[q];t[nq].val=t[p].val+1; 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][21],deep[N]; void dfs(int u){ dfn[u]=++dfc; for(int i=1;(1<<i)<=deep[u];i++) fa[u][i]=fa[ fa[u][i-1] ][i-1]; for(int i=h[u];i;i=e[i].ne) if(e[i].v!=fa[u][0]){ fa[e[i].v][0]=u; deep[e[i].v]=deep[u]+1; 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=19;i>=0;i--) if((1<<i)&bin) x=fa[x][i]; for(int i=19;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return x==y ? x : fa[x][0]; } 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] ? 1 : 0; 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]=0; } void VirTree(){ cnt=0; int n=read(); for(int i=1;i<=n;i++) a[i]=pos[read()]; sort(a+1,a+1+n); int p=0;a[++p]=a[1]; for(int i=2;i<=n;i++) if(a[i]!=a[i-1]) a[++p]=a[i]; n=p; sort(a+1,a+1+n,cmp); for(int i=1;i<=n;i++) key[a[i]]=1; int top=0; for(int i=1;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-1]]){ ins(f,st[top--]); if(f!=st[top]) st[++top]=f; break; }else ins(st[top-1],st[top]),top--; } st[++top]=x; } while(top>1) ins(st[top-1],st[top]),top--; ans=0; dp(st[1]); printf("%lld\n",ans); for(int i=1;i<=n;i++) key[a[i]]=0; } int main(){ freopen("in","r",stdin); n=read();Q=read(); scanf("%s",s+1); reverse(s+1,s+1+n); for(int i=1;i<=n;i++) extend(s[i]-'a'),pos[n-i+1]=last; for(int i=1;i<=sz;i++) ins(t[i].par,i); dfs(root); memset(h,0,sizeof(h)); while(Q--) VirTree(); }
Copyright:http://www.cnblogs.com/candy99/