CF504E Misha and LCP on Tree 题解

简单的hsh,每一次二分匹配,总共\(O(n)\)次询问,每一次二分答案,用哈希\(O(1)\)匹配,总复杂度\(O(n \log_2{n})\),直接暴力就可以写过了。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int base2=131;
const int base1=13331;
const int maxn=6e5+10;
const int inv1=598004655;
const int inv2=526717562;
const int modd1=1000000007;
const int modd2=1000000009;
int pwinv1[maxn],pwinv2[maxn],l,r,lca1,lca2,son[maxn];
int hsh1[maxn],hsh2[maxn],pw1[maxn],pw2[maxn],hs1[maxn],m;
int dep[maxn],hs2[maxn],n,x,y,xx,yy,len,lg[maxn],st[maxn][21];
int top[maxn],cnt,dfn[maxn],ans,lin1,lin2,fa[maxn][21],mxdep[maxn];
vector<int>u[maxn],v[maxn],tu[maxn];
string s;
int getz1(int q,int w){
	return (hsh1[w]-hsh1[q]*pw1[dep[w]-dep[q]]%modd1+modd1)%modd1;
}
int getz2(int q,int w){
	return (hsh2[w]-hsh2[q]*pw2[dep[w]-dep[q]]%modd2+modd2)%modd2;
}
int getd1(int q,int w){
	return (hs1[q]-hs1[fa[w][0]]+modd1)*pwinv1[dep[fa[w][0]]]%modd1;
}
int getd2(int q,int w){
	return (hs2[q]-hs2[fa[w][0]]+modd2)*pwinv2[dep[fa[w][0]]]%modd2;
}
int lca(int q,int w){
	q=dfn[q],w=dfn[w];
	if(q>w){
		swap(q,w);
	}
	int ll=lg[w-q+1];
	if(dep[st[q][ll]]<dep[st[w-(1<<ll)+1][ll]]){
		return st[q][ll];
	}
	else{
		return st[w-(1<<ll)+1][ll];
	}
}
pair<int,int> geths(int q,int w){
	int qw=lca(q,w);
	if(qw==w){
		return make_pair(getd1(q,w),getd2(q,w));
	}
	else if(qw==q){
		return make_pair(getz1(fa[q][0],w),getz2(fa[q][0],w));
	}
	return make_pair((getd1(q,qw)*pw1[dep[w]-dep[qw]]+getz1(qw,w))%modd1,(getd2(q,qw)*pw2[dep[w]-dep[qw]]+getz2(qw,w))%modd2);
}
void dfs(int q,int w){
	cnt++;
	dfn[q]=cnt;
	st[cnt][0]=q;
	fa[q][0]=w;
	for(int i=1;i<=20;i++){
		fa[q][i]=fa[fa[q][i-1]][i-1];
	}
	dep[q]=dep[w]+1;
	hsh1[q]=(hsh1[w]*base1+s[q-1]-'a')%modd1;
	hsh2[q]=(hsh2[w]*base2+s[q-1]-'a')%modd2;
	hs1[q]=((s[q-1]-'a')*pw1[dep[q]-1]+hs1[w])%modd1;
	hs2[q]=((s[q-1]-'a')*pw2[dep[q]-1]+hs2[w])%modd2;
	mxdep[q]=dep[q];
	for(int i=0;i<tu[q].size();i++){
		if(tu[q][i]!=w){
			dfs(tu[q][i],q);
			cnt++;
			st[cnt][0]=q;
			if(mxdep[tu[q][i]]>mxdep[son[q]]){
				son[q]=tu[q][i];
				mxdep[q]=mxdep[tu[q][i]];
			}
		}
	}
	return;
}
void dfs1(int q,int w){
	top[q]=w;
	if(q==w){
		for(int i=0,now=q;i<=mxdep[q]-dep[q];i++){
			u[q].push_back(now);
			now=fa[now][0];
		}
		for(int i=0,now=q;i<=mxdep[q]-dep[q];i++){
			v[q].push_back(now);
			now=son[now];
		}
	}
	if(son[q]){
		dfs1(son[q],w);
	}
	for(int i=0;i<tu[q].size();i++){
		if(tu[q][i]!=fa[q][0]&&tu[q][i]!=son[q]){
			dfs1(tu[q][i],tu[q][i]);
		}
	}
	return;
}
int get_fa(int q,int w){
	if(!w){
		return q;
	}
	q=fa[q][lg[w]];
	w=w-(1<<lg[w]);
	w=w-(dep[q]-dep[top[q]]);
	q=top[q];
	if(w>=0){
		return u[q][w];
	}
	else{
		return v[q][-w];
	}
}
int find(int q,int w,int qw,int wq){
	if(dep[q]-dep[w]+1>=wq){
		return get_fa(q,wq-1);
	}
	else{
		return get_fa(qw,dep[q]+dep[qw]-2*dep[w]+1-wq);
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	pw1[0]=pw2[0]=pwinv1[0]=pwinv2[0]=1;
	for(int i=1;i<=3e5;i++){
		pw1[i]=pw1[i-1]*base1%modd1;
		pw2[i]=pw2[i-1]*base2%modd2;
		pwinv1[i]=pwinv1[i-1]*inv1%modd1;
		pwinv2[i]=pwinv2[i-1]*inv2%modd2;
	}
	cin>>n>>s;
	for(int i=1;i<n;i++){
		cin>>x>>y;
		tu[x].push_back(y);
		tu[y].push_back(x);
	}
	dfs(1,0);
	dfs1(1,1);
	for(int i=2;i<=(n<<1);i++){
		lg[i]=lg[i>>1]+1;
	}
	for(int i=1;i<=20;i++){
		for(int j=1;j<=cnt-(1<<i)+1;j++){
			if(dep[st[j][i-1]]<dep[st[j+(1<<(i-1))][i-1]]){
				st[j][i]=st[j][i-1];
			}
			else{
				st[j][i]=st[j+(1<<(i-1))][i-1];
			}
		}
	}
	cin>>m;
	while(m--){
		cin>>x>>y>>xx>>yy;
		l=1;
		lca1=lca(x,y);
		lca2=lca(xx,yy);
		r=min(dep[x]+dep[y]-2*dep[lca1]+1,dep[xx]+dep[yy]-2*dep[lca2]+1);
		ans=0;
		while(l<=r){
			int mid=(l+r)/2;
			lin1=find(x,lca1,y,mid);
			lin2=find(xx,lca2,yy,mid);
			if(geths(x,lin1)==geths(xx,lin2)){
				l=mid+1;
				ans=mid;
			}
			else{
				r=mid-1;
			}
		}
		cout<<ans<<'\n';
	}
	return 0;
}
posted @ 2025-05-11 18:02  特别之处  阅读(11)  评论(0)    收藏  举报