BZOJ3879: SvT 后缀树 虚树
来源:互联网 发布:深圳市金软网络骗局 编辑:程序博客网 时间:2024/06/05 19:40
有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n].
现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示),求这些后缀两两之间的LCP(LongestCommonPrefix)的长度之和.一对后缀之间的LCP长度仅统计一遍.
怕忘记虚树怎么写于是挂个板子题。
LCP长度相当于后缀树上LCA深度,对于每个点统计有多少点对以它为LCA即可。按DFS序排序后反向扫一遍就相当于DFS。
#include<cstdio>#include<algorithm>#include<cstring>#define gm 500005using namespace std;typedef long long ll;struct node{ node *s[26],*pa; int dep; int no; bool used; node(int dep):s(),pa(),dep(dep),no(),used(){} void copy(const node &x) { memcpy(s,x.s,sizeof s); pa=x.pa; }};struct e{ int t; e *n; e(int t,e *n):t(t),n(n){}}*f[gm<<1];int dep[gm<<1],pos[gm],dfn[gm<<1],dis[gm<<1];int son[gm<<1],fat[gm<<1],top[gm<<1],sz[gm<<1],clk=0;struct cmp{bool operator() (int a,int b){return dfn[a]<dfn[b];}};void dfs1(int x){ sz[x]=1; for(e *i=f[x];i;i=i->n) { if(i->t==fat[x]) continue; fat[i->t]=x; dis[i->t]=dis[x]+1; dfs1(i->t); sz[x]+=sz[i->t]; if(sz[i->t]>sz[son[x]]) son[x]=i->t; }}void dfs2(int x){ dfn[x]=++clk; top[x]=(x==son[fat[x]]?top[fat[x]]:x); if(son[x]) dfs2(son[x]); for(e *i=f[x];i;i=i->n) { if(i->t==fat[x]||i->t==son[x]) continue; dfs2(i->t); }}int LCA(int a,int b){ while(top[a]!=top[b]) { if(dis[top[a]]<dis[top[b]]) a^=b^=a^=b; a=fat[top[a]]; } return dis[a]<dis[b]?a:b;}struct SAM{ node *rt,*last; SAM():rt(new node(0)),last(rt){} void push_back(char c) { c-='a'; node *np=new node(last->dep+1); node *p=last; last=np; for(;p&&!p->s[c];p=p->pa) p->s[c]=np; if(!p) { np->pa=rt; return; } node *q=p->s[c]; if(q->dep==p->dep+1) { np->pa=q; return; } node *nq=new node(p->dep+1); nq->copy(*q); q->pa=np->pa=nq; for(;p&&p->s[c]==q;p=p->pa) p->s[c]=nq; } void svt() { static node *q[gm<<1]; int l=0,r=0; int ct=0; q[++r]=rt; while(l!=r) { node *x=q[++l]; ++ct; if(x->no) pos[x->no]=ct; dep[x->no=ct]=x->dep; if(x->pa) { int u=x->pa->no,v=x->no; f[u]=new e(v,f[u]); } for(char i=0;i<26;++i) { node *y=x->s[i]; if(y&&!y->used) { y->used=1; q[++r]=y; } } } dfs1(1); dfs2(1); }}sam;char s[gm];int n,m;int a[3000001],tot;int stk[gm<<1],tp;int fa[gm<<1],cnt[gm<<1];void solve(){ int t; scanf("%d",&t); for(int i=1;i<=t;++i) scanf("%d",a+i),a[i]=pos[a[i]]; sort(a+1,a+t+1,cmp()); tot=unique(a+1,a+t+1)-a-1; stk[0]=tp=0; for(int i=1,j=tot;i<=j;++i) { int x=a[i]; cnt[x]=1; if(!tp) { fa[x]=0; stk[++tp]=x; } else { int lca=LCA(x,stk[tp]); while(tp&&dis[lca]<dis[stk[tp]]) { if(tp==1||dis[stk[tp-1]]<=dis[lca]) { fa[stk[tp]]=lca; } --tp; } if(stk[tp]!=lca) { a[++tot]=lca; cnt[lca]=0; fa[lca]=stk[tp]; stk[++tp]=lca; } fa[x]=stk[tp]; stk[++tp]=x; } } sort(a+1,a+tot+1,cmp()); ll ans=0; for(int i=tot;i>1;--i) { int x=a[i]; ans+=ll(cnt[x])*cnt[fa[x]]*dep[fa[x]]; cnt[fa[x]]+=cnt[x]; } printf("%lld\n",ans);}int main(){ scanf("%d%d%s",&n,&m,s); for(int i=n-1;~i;--i) { sam.push_back(s[i]); sam.last->no=i+1; } sam.svt(); for(int i=1;i<=m;++i) { solve(); } return 0;}
0 0
- 【BZOJ3879】SvT 后缀树+虚树
- BZOJ3879: SvT 后缀树 虚树
- BZOJ3879:SvT(后缀自动机+虚树)
- bzoj3879: SvT 后缀自动机
- [BZOJ3879]SvT(后缀数组+单调栈)
- bzoj3879 SvT(后缀数组+单调栈)
- [BZOJ3879] SvT
- [bzoj3879]SvT
- BZOJ3879 SvT
- bzoj3879 SvT
- 【BZOJ3879】SvT,后缀数组+单调栈维护sum
- BZOJ 3879 SvT 后缀树+虚树
- bzoj 3879: SvT 后缀自动机+后缀树+虚树
- [后缀自动机 后缀树 虚树] BZOJ 3879 SvT
- bzoj 3879: SvT 后缀自动机+虚树+树形dp
- bzoj3879
- SVT
- bzoj 3879 SvT 后缀数组 rmq 并查集
- Makefile经典教程
- lua require dofile loadfile 比较笔记
- 《C++ primer plus》读书笔记 博客目录
- 折半查找
- Delphi预编译指令总结
- BZOJ3879: SvT 后缀树 虚树
- 同时开发两款H5的ARPG游戏的设计和实践
- box-sizing常用的属性有哪些?分别有什么作用?
- 访问网络文件共享服务
- Java压缩算法性能比较
- 基本数据类型和引用数据类型的参数传递
- java使用一维数组输出杨辉三角
- Android简单网络音乐播放器
- FFmpeg总结(十)用ffmpeg进行在视频中加水印图、加gif图