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

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.
特别注意:由于另一世界线的某些参数发生了变化,对于一组询问,即使一个后缀出现了多次,也仅算一次.
 
正解:后缀自动机+后缀树+虚树。
还是一样的套路。反串后缀自动机构出后缀树,然后我们每次可以建一棵虚树来搞树形$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的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3879: SvT

bzoj3879 SvT

zoj千题计划312:bzoj3879: SvT(后缀数组+st表+单调栈)

bzoj3879

Educational Codeforces Round 53 (Rated for Div. 2)G. Yet Another LCP Problem

HDU 3879:Base Station(最大权闭合图)