• 【题解】CF1107G Vasya and Maximum Profit


    题目链接

    题目大意:

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

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

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

    (1leqslant n,qleqslant 2cdot10^5,1leqslant k,lleqslant n,sum kleqslant 2cdot10^5,sum lleqslant 2cdot10^5),集合升序给出。

    先考虑单个询问的做法。

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

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

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

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

    code:

    #include<stdio.h>
    #include<vector>
    #include<memory.h>
    #include<algorithm>
    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<<i);j++)
    			st[j][i]=d[st[j][i-1]]<d[st[j+(1<<i-1)][i-1]]?st[j][i-1]:st[j+(1<<i-1)][i-1];
    }
    int lca(int p,int q){
    	if(p==q)return p;
    	p=pos[p];q=pos[q];
    	if(p>q)p^=q^=p^=q;
    	int h=log_2[q-p+1];
    	return d[st[p][h]]<d[st[q-(1<<h)+1][h]]?st[p][h]:st[q-(1<<h)+1][h];
    }
    int cnt1[600002],cnt2[600002],f[600002];
    unsigned long long calc(int p){//累加贡献
    	unsigned long long ans=0;
    	for(int i=Last[p];i;i=Next[i])ans+=calc(i),cnt1[p]+=cnt1[i],cnt2[p]+=cnt2[i];
    	return ans+(p==1?0:1ull*cnt1[p]*cnt2[p]*(d[p]-d[f[p]]));
    }
    std::vector<int>V,S;
    void solve(std::vector<int>&A,std::vector<int>&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]<t[q];});
    	V.resize(std::unique(V.begin(),V.end())-V.begin());
    	int n=V.size();
    	for(int i=1;i<n;i++)V.push_back(lca(V[i-1],V[i]));//找出虚树的所有节点
    	std::sort(V.begin(),V.end(),[](int p,int q){return t[p]<t[q];});
    	V.resize(std::unique(V.begin(),V.end())-V.begin());
    	for(int &i:V){
    		while(!S.empty()&&r[S.back()]<t[i])S.pop_back();
    		if(!S.empty())Next[i]=Last[f[i]=S.back()],Last[S.back()]=i;//建虚树
    		S.push_back(i);
    	}S.clear();
    	for(int &p:A)cnt1[a[p]]++;
    	for(int &p:B)cnt2[a[p]]++;
    	printf("%lld
    ",calc(1));
    	for(int &p:V)cnt1[p]=cnt2[p]=Last[p]=Next[p]=0;
    	V.clear();
    }
    int main(){
    	scanf("%d%d%s",&n,&m,c+1);
    	build();st_init();
    	memset(Last,0,sizeof(Last));
    	memset(Next,0,sizeof(Next));
    	std::vector<int>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();
    	}
    }
    
  • 相关阅读:
    ClickHouse 监控及备份 (三)ClickHouse 配置
    ClickHouse 监控及备份 (二)Prometheus&Grafana 的安装
    ClickHouse 监控及备份 (一)ClickHouse 监控概述
    ClickHouse 高级(八)运维(1)常见问题排查
    ClickHouse 高级(七)MaterializeMySQL 引擎
    ClickHouse 高级(六)物化视图
    使用Iperf调整网络
    WinForm中DataGridView的使用(四)
    数据库设计经验总结
    WinForm使用Label控件模拟分割线(竖向)
  • 原文地址:https://www.cnblogs.com/ztc03/p/12364607.html
Copyright © 2020-2023  润新知