bzoj3879 SvT
Posted wfj_2048
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3879 SvT相关的知识,希望对你有一定的参考价值。
Description
(我并不想告诉你题目名字是什么鬼)
有一个长度为n的仅包含小写字母的字符串S,下标范围为[1,n].
现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在S中出现的起始位置来表示),求这些后缀两两之间的LCP(LongestCommonPrefix)的长度之和.一对后缀之间的LCP长度仅统计一遍.
Input
第一行两个正整数n,m,分别表示S的长度以及询问的次数.
接下来一行有一个字符串S.
接下来有m组询问,对于每一组询问,均按照以下格式在一行内给出:
首先是一个整数t,表示共有多少个后缀.接下来t个整数分别表示t个后缀在字符串S中的出现位置.
Output
对于每一组询问,输出一行一个整数,表示该组询问的答案.由于答案可能很大,仅需要输出这个答案对于23333333333333333(一个巨大的质数)取模的余数.
Sample Input
7 3
popoqqq
1 4
2 3 5
4 1 2 5 6
popoqqq
1 4
2 3 5
4 1 2 5 6
Sample Output
0
0
2
Hint
样例解释:
对于询问一,只有一个后缀”oqqq”,因此答案为0.
对于询问二,有两个后缀”poqqq”以及”qqq”,两个后缀之间的LCP为0,因此答案为0.
对于询问三,有四个后缀”popoqqq”,”opoqqq”,”qqq”,”qq”,其中只有”qqq”,”qq”两个后缀之间的LCP不为0,且长度为2,因此答案为2.
对于100%的测试数据,有S<=5*10^5,且Σt<=3*10^6.
特别注意:由于另一世界线的某些参数发生了变化,对于一组询问,即使一个后缀出现了多次,也仅算一次.
0
2
Hint
样例解释:
对于询问一,只有一个后缀”oqqq”,因此答案为0.
对于询问二,有两个后缀”poqqq”以及”qqq”,两个后缀之间的LCP为0,因此答案为0.
对于询问三,有四个后缀”popoqqq”,”opoqqq”,”qqq”,”qq”,其中只有”qqq”,”qq”两个后缀之间的LCP不为0,且长度为2,因此答案为2.
对于100%的测试数据,有S<=5*10^5,且Σt<=3*10^6.
特别注意:由于另一世界线的某些参数发生了变化,对于一组询问,即使一个后缀出现了多次,也仅算一次.
正解:后缀自动机+后缀树+虚树。
还是一样的套路。反串后缀自动机构出后缀树,然后我们每次可以建一棵虚树来搞树形$dp$。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define M (6000010) 6 #define N (1000010) 7 8 using namespace std; 9 10 struct edge{ int nt,to; }g[N<<1]; 11 12 int head[N],top[N],fa[N],son[N],Sz[N],dep[N],dfn[N],ed[N],val[N],vis[N],a[M],st[M],n,m,num,cnt; 13 int ch[N][26],l[N],sz[N],pos[N],la,tot,len; 14 char s[N]; 15 ll ans; 16 17 il int gi(){ 18 RG int x=0,q=1; RG char ch=getchar(); 19 while ((ch<‘0‘ || ch>‘9‘) && ch!=‘-‘) ch=getchar(); 20 if (ch==‘-‘) q=-1,ch=getchar(); 21 while (ch>=‘0‘ && ch<=‘9‘) x=x*10+ch-48,ch=getchar(); 22 return q*x; 23 } 24 25 il void add(RG int c){ 26 RG int p=la,np=++tot; la=np,l[np]=l[p]+1,sz[np]=1; 27 for (;p && !ch[p][c];p=fa[p]) ch[p][c]=np; 28 if (!p){ fa[np]=1; return; } RG int q=ch[p][c]; 29 if (l[q]==l[p]+1) fa[np]=q; else{ 30 RG int nq=++tot; l[nq]=l[p]+1; 31 fa[nq]=fa[q],fa[q]=fa[np]=nq; 32 memcpy(ch[nq],ch[q],sizeof(ch[q])); 33 for (;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 34 } 35 return; 36 } 37 38 il void insert(RG int from,RG int to){ 39 g[++num]=(edge){head[from],to},head[from]=num; return; 40 } 41 42 il void dfs1(RG int x){ 43 dep[x]=dep[fa[x]]+1,Sz[x]=1; RG int v; 44 for (RG int i=head[x];i;i=g[i].nt){ 45 v=g[i].to,dfs1(v),Sz[x]+=Sz[v]; 46 if (Sz[son[x]]<=Sz[v]) son[x]=v; 47 } 48 return; 49 } 50 51 il void dfs2(RG int x,RG int anc){ 52 top[x]=anc,dfn[x]=++cnt; 53 if (son[x]) dfs2(son[x],anc); 54 for (RG int i=head[x];i;i=g[i].nt) 55 if (g[i].to!=son[x]) dfs2(g[i].to,g[i].to); 56 ed[x]=cnt; return; 57 } 58 59 il void dfs(RG int x){ 60 val[x]=vis[x]*sz[x]; 61 for (RG int i=head[x],v;i;i=g[i].nt){ 62 v=g[i].to,dfs(v); 63 ans+=1LL*l[x]*val[x]*val[v],val[x]+=val[v]; 64 } 65 return; 66 } 67 68 il int lca(RG int u,RG int v){ 69 while (top[u]!=top[v]){ 70 if (dep[top[u]]<dep[top[v]]) swap(u,v); 71 u=fa[top[u]]; 72 } 73 return dep[u]<dep[v] ? u : v; 74 } 75 76 il int cmp(const int &a,const int &b){ return dfn[a]<dfn[b]; } 77 78 int main(){ 79 #ifndef ONLINE_JUDGE 80 freopen("svt.in","r",stdin); 81 freopen("svt.out","w",stdout); 82 #endif 83 n=gi(),m=gi(),la=++tot,scanf("%s",s+1); 84 for (RG int i=n;i;--i) add(s[i]-‘a‘),pos[i]=la; 85 for (RG int i=2;i<=tot;++i) insert(fa[i],i); dfs1(1),dfs2(1,1); 86 for (RG int i=1;i<=tot;++i) head[i]=0; num=0; 87 while (m--){ 88 RG int t=gi(),tt=t; for (RG int i=1;i<=t;++i) a[i]=pos[gi()],vis[a[i]]=1; sort(a+1,a+t+1,cmp); 89 for (RG int i=2;i<=t;++i) if (ed[a[i-1]]<dfn[a[i]]) a[++tt]=lca(a[i-1],a[i]); 90 sort(a+1,a+tt+1,cmp),tt=unique(a+1,a+tt+1)-a-1; RG int top=1; st[top]=a[1]; 91 for (RG int i=2;i<=tt;++i){ 92 while (ed[st[top]]<dfn[a[i]]) --top; 93 insert(st[top],a[i]),st[++top]=a[i]; 94 } 95 ans=0,dfs(a[1]),printf("%lld\n",ans),num=0; 96 for (RG int i=1;i<=tt;++i) head[a[i]]=vis[a[i]]=0; 97 } 98 return 0; 99 }
以上是关于bzoj3879 SvT的主要内容,如果未能解决你的问题,请参考以下文章
zoj千题计划312:bzoj3879: SvT(后缀数组+st表+单调栈)
Educational Codeforces Round 53 (Rated for Div. 2)G. Yet Another LCP Problem