Yet Another LCP Problem[CF1073G][后缀自动机,虚树]

文章目录

题目

Luogu
在这里插入图片描述
在这里插入图片描述

思路

也就是询问一些后缀的前缀
然后翻转变为查询前缀的后缀
建立后缀自动机
对于一个串由于在 f a i l fail 树上爬时候是它的后缀
那么预处理每个前缀 i i 代表结点 e d i ed_i
那么两个前缀 u , v u,v 最长的 l c s lcs 就是 l c a ( e d u , e d v ) lca(ed_u,ed_v)
然后以 u u l c a lca 的贡献为
s i z a p s i z b q l e n u + \sum siza_p*sizb_q*len_u+。。。
其中 p , q p,q u u 的不同儿子
当然也可以这样:
s i z a u s i z b u ( l e n u l e n f a ) siza_u*sizb_u*(len_u-len_{fa})
也就是把每一对的 l c s lcs 拆分计算
然后建立虚树即可

代码

#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<cstdio>    
#include<queue>    
#include<cmath>    
#include<vector>    
#include<cstring>   
#include<climits>    
#include<iostream>   
#include<algorithm>
using namespace std;
#define LL long long
#define ULL unsigned long long
int read(){
    int f=1,x=0;char c=getchar();
    while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
    while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
    return f*x;
}
#define MAXN 800000
#define INF 0x3f3f3f3f
int scnt,Root,lst,maxlen[MAXN+5],nxt[MAXN+5][26],fail[MAXN+5],ed[MAXN+5];
void Init(){
	scnt=Root=lst=1;
	return ;
}
void Extend(int c,int id){
	int p=lst,cur=++scnt;
	ed[id]=cur;
	maxlen[cur]=maxlen[p]+1,lst=cur;
	while(p&&!nxt[p][c])
		nxt[p][c]=cur,p=fail[p];
	if(!p){
		fail[cur]=1;
		return ;
	}
	int q=nxt[p][c];
	if(maxlen[q]==maxlen[p]+1){
		fail[cur]=q;
		return ;
	}
	int clone=++scnt;
	maxlen[clone]=maxlen[p]+1;
	memcpy(nxt[clone],nxt[q],sizeof(nxt[q]));
	fail[clone]=fail[q];
	fail[cur]=fail[q]=clone;
	while(p&&nxt[p][c]==q)
		nxt[p][c]=clone,p=fail[p];
	return ;
}
vector<int> E[MAXN+5],G[MAXN+5];
int lg2[MAXN+5],dcnt,dfn[MAXN+5],dep[MAXN+5],st[20][MAXN+5];
void DFS(int u){
	dfn[u]=++dcnt,st[0][dcnt]=u;
	for(int i=0;i<(int)E[u].size();i++){
		int v=E[u][i];
		dep[v]=dep[u]+1;
		DFS(v);
		st[0][++dcnt]=u;
	}
	return ;
}
void Prepare(){
	for(int i=2;i<=dcnt;i++)
		lg2[i]=lg2[i>>1]+1;
	for(int i=1;i<=19;i++)
		for(int j=1;j<=dcnt;j++){
			int x=st[i-1][j],y=st[i-1][j+(1<<(i-1))];
			st[i][j]=(dep[x]<dep[y]?x:y);
		}
	return ;
}
int Lca(int u,int v){
	u=dfn[u],v=dfn[v];
	if(u>v) swap(u,v);
	int i=lg2[v-u+1],a=st[i][u],b=st[i][v-(1<<i)+1];
	return dep[a]<dep[b]?a:b;
}
LL ans;
int siza[MAXN+5],sizb[MAXN+5];
int acnt,a[MAXN+5],tp,stk[MAXN+5];
bool vis[MAXN+5],va[MAXN+5],vb[MAXN+5];
void DFS2(int u,int ff){
	siza[u]=va[u],sizb[u]=vb[u];
	for(int i=0;i<(int)G[u].size();i++){
		int v=G[u][i];
		DFS2(v,u),siza[u]+=siza[v],sizb[u]+=sizb[v];
	}
	ans+=1ll*siza[u]*sizb[u]*(maxlen[u]-maxlen[ff]);
	return ;
}
char S[MAXN+5];
bool cmp(int a,int b){return dfn[a]<dfn[b];}
int main(){
	int n=read(),q=read();
	scanf("%s",S+1);
	Init();
	for(int i=n;i>=1;i--)
		Extend(S[i]-'a',i);
	for(int i=2;i<=scnt;i++)
		E[fail[i]].push_back(i);
	DFS(Root);
	Prepare();
	for(int t=1;t<=q;t++){
		acnt=0;
		int k=read(),l=read();
		for(int i=1;i<=k;i++){
			int x=read();
			a[++acnt]=ed[x],vis[ed[x]]=1,va[ed[x]]=1;
		}
		for(int i=1;i<=l;i++){
			int x=read();
			a[++acnt]=ed[x],vis[ed[x]]=1,vb[ed[x]]=1;
		}
		sort(a+1,a+acnt+1,cmp);
		for(int tmp=acnt,i=1;i<tmp;i++){
			int lca=Lca(a[i],a[i+1]);
			if(!vis[lca])
				vis[lca]=1,a[++acnt]=lca;
		}
		sort(a+1,a+acnt+1,cmp);
		tp=0,stk[++tp]=a[1];
		for(int i=2;i<=acnt;i++){
			if(a[i]==a[i-1]) continue;
			while(tp>1&&Lca(stk[tp],a[i])!=stk[tp])
				tp--;
			G[stk[tp]].push_back(a[i]);
			//printf("%d %d\n",stk[tp],a[i]);
			stk[++tp]=a[i];
		}
		ans=0,DFS2(a[1],0);
		printf("%lld\n",ans);
		for(int i=1;i<=acnt;i++)
			G[a[i]].clear(),vis[a[i]]=0,va[a[i]]=0,vb[a[i]]=0;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37555704/article/details/106437084