【题解】CF1107G Vasya and Maximum Profit

题目链接

题目大意:

\(\text{LCP}(s,t)\)\(s\)\(t\)的最长公共前缀,\(s[i\cdots j]\)\(s\)中从第\(i\)个字符到第\(j\)个字符的子串。

给你一个长度为\(n\)的字符串\(s\)\(q\)个询问,每个询问包含两个集合\(a_1,a_2,\cdots,a_k\)\(b_1,b_2,\cdots,b_l\),求

\[\sum_{i=1}^k\sum_{j=1}^l\text {LCP}(s[a_i,\cdots,n],s[b_j,\cdots,n]) \]

\(1\leqslant n,q\leqslant 2\cdot10^5,1\leqslant k,l\leqslant n,\sum k\leqslant 2\cdot10^5,\sum l\leqslant 2\cdot10^5\),集合升序给出。

先考虑单个询问的做法。

暴力显然会\(\text{T}\),看到后缀的\(\text{LCP}\),容易想到后缀树。

考虑在后缀树上做树上差分,维护每条边在插入第一/二个集合时经过的次数,两个次数乘起来,在乘以边长,就是这条边对答案的贡献。

多个询问怎么办?直接建虚树。

(感觉太短了就又在后面加了一行)

code:

#include
#include
#include
#include
struct node{
	node *s[26],*f;
	int maxx;
}tr[600002],*top=tr-1,*null=tr,*lt,*rt;
node *addnode(int maxx){
	node *p=++top;p->f=null;p->maxx=maxx;
	for(int i=0;i<26;i++)p->s[i]=null;
	return p;
}
int n,m,Last[600002],Next[600002],a[600002],d[600002],N;
char c[200002];
void build(){
	addnode(0);lt=rt=addnode(0);
	for(int i=n,j=1;i>0;i--,j++){//建反串的SAM,其parent树即为后缀树
		node *p=addnode(j);a[j]=p-tr;
		while(1){
			if(lt->s[c[i]-'a']==null)lt->s[c[i]-'a']=p,lt=lt->f;
			else{
				if(lt->s[c[i]-'a']->maxx==lt->maxx+1)p->f=lt->s[c[i]-'a'];
				else{
					node *t=addnode(lt->maxx+1),*q=lt->s[c[i]-'a'];
					memcpy(t->s,q->s,sizeof(q->s));t->f=q->f;q->f=p->f=t;
					while(lt->s[c[i]-'a']==q)lt->s[c[i]-'a']=t,lt=lt->f;
				}break;
			}if(lt==null){
				p->f=rt;break;
			}
		}lt=p;
	}for(int i=top-tr;i>1;i--){//后缀树
		int f=(tr+i)->f-tr;d[i]=(tr+i)->maxx;
		Next[i]=Last[f];Last[f]=i;
	}N=top-tr;
}
int t[600002],r[600002],st[1200002][21],pos[600002],tp1=0,tp2=0,log_2[1200002];
void dfs(int p){
	t[p]=++tp1;st[pos[p]=++tp2][0]=p;
	for(int i=Last[p];i;i=Next[i])dfs(i),st[++tp2][0]=p;
	r[p]=tp1;
}
void st_init(){//st表求LCA
	dfs(1);
	for(int i=2;i<=N<<1;i++)log_2[i]=log_2[i>>1]+1;
	for(int i=1;i<=log_2[N<<1];i++)
		for(int j=1;j<=N+N-(1<q)p^=q^=p^=q;
	int h=log_2[q-p+1];
	return d[st[p][h]]V,S;
void solve(std::vector&A,std::vector&B){
	V.push_back(1);
	for(int &p:A)V.push_back(a[p]);
	for(int &p:B)V.push_back(a[p]);
	std::sort(V.begin(),V.end(),[](int p,int q){return t[p]A,B;
	while(m--){
		int p,q,r;scanf("%d%d",&p,&q);
		while(p--)scanf("%d",&r),A.push_back(n+1-r);
		while(q--)scanf("%d",&r),B.push_back(n+1-r);
		solve(A,B);
		A.clear();B.clear();
	}
}

你可能感兴趣的:(【题解】CF1107G Vasya and Maximum Profit)