BZOJ3879:SvT(后缀自动机+虚树)
来源:互联网 发布:人体尺度数据测绘图 编辑:程序博客网 时间:2024/06/11 13:08
日更两篇,真刺激。
题目
题意:给出一个串,若干个询问。每个询问给出一些后缀,问它们两两之间LCP的长度和。
后缀数组的写法太简单显然了,把后缀按顺序拿出来,只用一个单调栈就可以了,但我并不会…所以就是SAM了。
经过一轮求后缀LCP模型在SAM上乱套,发现就是反串建SAM,得到后缀树。后缀树上结点的LCA的长度就是LCP长度。对于这里,把询问给出的结点在后缀树上建出虚树,每个点算贡献即可。
具体是这样的,对于x的两个儿子son1和son2,
#include <iostream>#include <fstream>#include <algorithm>#include <cmath>#include <ctime>#include <cstdio>#include <cstdlib>#include <cstring>using namespace std;#define mmst(a, b) memset(a, b, sizeof(a))#define mmcp(a, b) memcpy(a, b, sizeof(b))typedef long long LL;const int N=1001000;const LL mo=23333333333333333;void read(int &hy){ hy=0; char cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') { hy=(hy<<3)+(hy<<1)+cc-'0'; cc=getchar(); }}int n,m,k,a[N];int son[N][26],pre[N],dep[N],w[N],cnt=1,last=1;int head[N],nex[N],to[N],cur;int Chtholly[N],top[N],len[N],tim[N],siz[N],times;int st[N];char cc[N];LL ans;bool vis[N];void Insert(int x,int num){ dep[++cnt]=dep[last]+1; w[num]=cnt; int np=cnt,p=last; last=cnt; for(;!son[p][x];p=pre[p]) son[p][x]=np; if(!p) pre[np]=1; else { int q=son[p][x]; if(dep[q]==dep[p]+1) pre[np]=q; else { dep[++cnt]=dep[p]+1; int nq=cnt; pre[nq]=pre[q]; pre[q]=pre[np]=nq; mmcp(son[nq],son[q]); for(;son[p][x]==q;p=pre[p]) son[p][x]=nq; } }}void add(int u,int v){ to[++cur]=v; nex[cur]=head[u]; head[u]=cur;}void dfs(int x){ siz[x]=1; tim[x]=++times; for(int h=head[x];h;h=nex[h]) { len[to[h]]=len[x]+1; dfs(to[h]); siz[x]+=siz[to[h]]; if(siz[to[h]]>siz[Chtholly[x]]) Chtholly[x]=to[h]; }}void dfs2(int x,int tp){ top[x]=tp; if(Chtholly[x]) dfs2(Chtholly[x],tp); for(int h=head[x];h;h=nex[h]) if(to[h]!=Chtholly[x]) dfs2(to[h],to[h]);}int lca(int x,int y){ while(top[x]!=top[y]) { if(len[top[x]]<len[top[y]]) swap(x,y); x=pre[top[x]]; } return len[x]<len[y] ? x : y;}bool cmp(int x,int y){ return tim[x]<tim[y];}void dp(int x){ siz[x]=vis[x] ? 1 : 0; for(int h=head[x];h;h=nex[h]) { dp(to[h]); ans+=(LL)siz[to[h]]*siz[x]*dep[x]; siz[x]+=siz[to[h]]; } head[x]=0;}void work(){ ans=0; k=cur=0; int kk; read(kk); for(int i=1;i<=kk;i++) { int by; read(by); if(!vis[w[by]]) a[++k]=w[by]; vis[w[by]]=1; } sort(a+1,a+k+1,cmp); int t=0; for(int i=1;i<=k;i++) { if(!t) { st[++t]=a[i]; continue; } int lc=lca(a[i],st[t]); while(lc!=st[t]) { if(tim[lc]>=tim[st[t-1]]) { add(lc,st[t--]); if(lc!=st[t]) st[++t]=lc; break; } else add(st[t-1],st[t]),t--; } st[++t]=a[i]; } while(t!=1) add(st[t-1],st[t]),t--; dp(st[1]); for(int i=1;i<=k;i++) vis[a[i]]=0; printf("%lld\n",ans);}int main(){ cin>>n>>m; scanf("%s",cc); for(int i=n;i>=1;i--) Insert(cc[i-1]-'a',i); for(int i=2;i<=cnt;i++) add(pre[i],i); dfs(1); dfs2(1,1); mmst(head,0); while(m--) work(); return 0;}
阅读全文
0 0
- BZOJ3879:SvT(后缀自动机+虚树)
- bzoj3879: SvT 后缀自动机
- 【BZOJ3879】SvT 后缀树+虚树
- BZOJ3879: SvT 后缀树 虚树
- [BZOJ3879]SvT(后缀数组+单调栈)
- bzoj3879 SvT(后缀数组+单调栈)
- [BZOJ3879] SvT
- [bzoj3879]SvT
- BZOJ3879 SvT
- bzoj3879 SvT
- bzoj 3879: SvT 后缀自动机+后缀树+虚树
- [后缀自动机 后缀树 虚树] BZOJ 3879 SvT
- 【BZOJ3879】SvT,后缀数组+单调栈维护sum
- bzoj 3879: SvT 后缀自动机+虚树+树形dp
- BZOJ 3879 SvT 后缀树+虚树
- bzoj 3879: SvT (后缀数组+单调栈)
- 【后缀自动机】【SAM】【自动机】【数据结构】后缀自动机理解(入门)
- bzoj3879
- 全球范围内,有哪些组织或公司获得了TMMi的认证?
- 数据结构绪论习题篇
- Spring Boot配置文件-多环境配置
- TestNG入门教程-7-invocationCount和invocationTimeOut
- 线性代数之五:正交性
- BZOJ3879:SvT(后缀自动机+虚树)
- div中img图片下方空白问题,div高度不等于img图片的高度,会留出几个像素
- 被解救的Django【6】
- Luogu-1886 (单调队列)
- 这里多是闲逛论坛之后,一些有趣的知识整理
- Map的四种遍历
- Java中String类里的一些常用方法
- 动态规划-3.9 0-1背包问题
- 从m个数中选择n个数的实现