zoukankan      html  css  js  c++  java
  • CF504E Misha and LCP on Tree(树链剖分+后缀树组)

    1A真舒服。
    喜闻乐见的树链剖分+SA。
    一个初步的想法就是用树链剖分,把两个字符串求出然后hash+二分求lcp。。。不存在的。
    因为考虑到这个字符串是有序的,我们需要把每一条重链对应的字符串和这个重链反过来对应的字符串拼起来构成一个新的字符串。我们用树链剖分拼出两个字符串。用树剖拼出的这两个字符串,一定是重链拼成的字符串上一个一个区间,我们记录这些区间的左右端点。然后我们就是要一个一个处理区间。求两个区间对应字符串的lcp,我们直接上SA+ST表就行,求出lcp之后就在这些区间上分情况讨论,然后就结束了。
    具体看代码,太丑了也看不出来什么。

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=601000;
    int cnt,head[N];
    int size[N],fa[N],dep[N],dfn[N],top[N],tot,son[N];
    int s[N],id[N][2],cn,Top[N];
    int sa[N],x[N],y[N],len,rk[N],height[N],m,mn[N][20],c[N];
    int L[N][2],R[N][2],NUM[N],Num[N],n;
    char S[N];
    struct edge{
    	int to,nxt;
    }e[N];
    void add(int u,int v){
    	cnt++;
    	e[cnt].nxt=head[u];
    	e[cnt].to=v;
    	head[u]=cnt;
    }
    void dfs1(int u,int f){
    	size[u]=1;
    	fa[u]=f;
    	dep[u]=dep[f]+1;
    	int maxson=-1;
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(v==f)continue;
    		dfs1(v,u);
    		if(size[v]>maxson){
    			maxson=size[v];
    			son[u]=v;
    		}
    		size[u]+=size[v];
    	}
    }
    void dfs2(int u,int tp){
    	dfn[u]=++tot;
    	top[u]=tp;
    	if(son[u])dfs2(son[u],tp);
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(v==fa[u]||v==son[u])continue;
    		Top[++cn]=v;
    		dfs2(v,v);
    	}
    }
    void build(int u){
    	s[++len]=S[u];
    	id[dfn[u]][0]=len;
    	if(son[u]==0){
    		id[dfn[u]][0]=len;
    		s[++len]=S[u];
    		id[dfn[u]][1]=len;
    		return;
    	}
    	build(son[u]);
    	s[++len]=S[u];
    	id[dfn[u]][1]=len;
    }
    void get_sa(){
    	for(int i=1;i<=len;i++)c[x[i]=s[i]]++;
    	for(int i=1;i<=m;i++)c[i]+=c[i-1];
    	for(int i=len;i>=1;i--)sa[c[x[i]]--]=i;
    	for(int k=1;k<=len;k<<=1){
    		int num=0;
    		for(int i=len-k+1;i<=len;i++)y[++num]=i;
    		for(int i=1;i<=len;i++)if(sa[i]>k)y[++num]=sa[i]-k;
    		for(int i=1;i<=m;i++)c[i]=0;
    		for(int i=1;i<=len;i++)c[x[i]]++;
    		for(int i=1;i<=m;i++)c[i]+=c[i-1];
    		for(int i=len;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
    		for(int i=1;i<=len;i++)swap(x[i],y[i]);
    		x[sa[1]]=1;num=1;
    		for(int i=2;i<=len;i++)
    			x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
    		if(num==len)break;
    		m=num;
    	}
    }
    void get_height(){
    	int k=0;
    	for(int i=1;i<=len;i++)rk[sa[i]]=i;
    	for(int i=1;i<=len;i++){
    		if(rk[i]==1)continue;
    		if(k)k--;
    		int j=sa[rk[i]-1];
    		while(i+k<=len&&j+k<=len&&s[i+k]==s[j+k])k++;
    		height[rk[i]]=k;
    	}
    }
    void pre_work(){
    	for(int i=1;i<=len;i++)mn[i][0]=height[i];
    	int Len=log2(len);
    	for(int j=1;j<=Len;j++)
    		for(int i=1;i+(1<<j)-1<=len;i++)
    			mn[i][j]=min(mn[i][j-1],mn[i+(1<<j-1)][j-1]); 
    }
    int get_lcp(int l,int r){
    	if(l>r)swap(l,r);
    	l++;
    	if(l>r)return 1e9;
    	int Len=log2(r-l+1);
    	return min(mn[l][Len],mn[r-(1<<Len)+1][Len]);
    }
    void work(int x,int y,int k){
    	while(top[x]!=top[y]){
    		if(dep[top[x]]>dep[top[y]]){
    			Num[k]++;
    			L[Num[k]][k]=id[dfn[x]][1];
    			R[Num[k]][k]=id[dfn[top[x]]][1];
    			x=fa[top[x]];
    		}
    		else{
    			NUM[k]--;
    			L[NUM[k]][k]=id[dfn[top[y]]][0];
    			R[NUM[k]][k]=id[dfn[y]][0];
    			y=fa[top[y]];
    		}
    	}
    	if(dep[x]>dep[y]){
    		Num[k]++;
    		L[Num[k]][k]=id[dfn[x]][1];
    		R[Num[k]][k]=id[dfn[y]][1];
    	}
    	else{
    		NUM[k]--;
    		L[NUM[k]][k]=id[dfn[x]][0];
    		R[NUM[k]][k]=id[dfn[y]][0];
    	}
    }
    void calc(){
    	int now0=1,now1=1;
    	int tmp=0;
    	while(now0<=n&&now1<=n){
    		if(now0>Num[0]&&now0<NUM[0])now0=NUM[0];
    		if(now1>Num[1]&&now1<NUM[1])now1=NUM[1];
    		if(now0>n||now1>n)break;
    		int LL=min(min(R[now0][0]-L[now0][0]+1,R[now1][1]-L[now1][1]+1),get_lcp(rk[L[now0][0]],rk[L[now1][1]]));
    		L[now0][0]=L[now0][0]+LL;
    		L[now1][1]=L[now1][1]+LL;
    		tmp+=LL;
    		if(L[now0][0]<=R[now0][0]&&L[now1][1]<=R[now1][1])break;
    		if(L[now0][0]>R[now0][0])now0++;
    		if(L[now1][1]>R[now1][1])now1++;
    	}
    	printf("%d
    ",tmp);
    }
    int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return sum*f;
    }
    int main(){
    	n=read();
    	scanf("%s",S+1);
    	for(int i=1;i<n;i++){
    		int u=read(),v=read();
    		add(u,v);add(v,u);
    	}
    	dfs1(1,0);cn=1;Top[1]=1;dfs2(1,1);
    	for(int i=1;i<=cn;i++)build(Top[i]);
    	m=122;
    	get_sa();get_height();pre_work();
    	m=read();
    	int a,b,c,d;
    	while(m--){
    		a=read();b=read();
    		c=read();d=read();
    		Num[0]=Num[1]=0;
    		NUM[0]=NUM[1]=n+1;
    		work(a,b,0);work(c,d,1);
    		calc();
    	}
    	return 0;
    }
    
  • 相关阅读:
    Live2d Test Env
    Live2d Test Env
    Spring Boot GraphQL 实战 02_增删改查和自定义标量
    Spring Boot GraphQL 实战 01_快速入门
    【MacBook】 SSH使用
    一个神奇的没有springboot注释的api文档生成器---JApiDocs
    Spring Cloud Alibaba 06:Gateway服务网关
    leetcode-300. 最长递增子序列
    leetcode-309. 最佳买卖股票时机含冷冻期
    leetcode-121. 买卖股票的最佳时机
  • 原文地址:https://www.cnblogs.com/Xu-daxia/p/10211618.html
Copyright © 2011-2022 走看看