【题解】Luogu P9399 「DBOI」Round 1 人生如树

新加的点不会影响之前的询问,所以直接离线,先把所有点都建好。

将问题转化为:用 \(b\) 数组减去 \(a\) 数组,得到的形如 \(1,2,3,\dots\) 的等差序列的最大长度。

考虑将两个序列哈希,预处理出等差数列的哈希值,二分长度即可。而在树上维护路径数组的哈希值,可以用倍增解决。

时间复杂度 \(O(m\log^2n)\)

#include<bits/stdc++.h>
#define ll long long
#define il inline
#define ull unsigned ll
#define pb push_back
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=2e5+5;
const ull bas1=13331;
const ll bas2=13327,mod2=1e9+7;
int n,m,q,T,_2[22];
int a[maxn],dep[maxn];
int anc[maxn][22];
vector<int> e[maxn];
struct wnti{
	int u1,v1,u2,v2;
}wt[maxn];
ull tar1[maxn],pw1[maxn];
ull up1[maxn][22],dw1[maxn][22];
ll tar2[maxn],pw2[maxn];
ll up2[maxn][22],dw2[maxn][22];
il void dfs(int u,int fa){
	anc[u][0]=fa,dep[u]=dep[fa]+1;
	up1[u][0]=dw1[u][0]=a[u]*pw1[1];
	up2[u][0]=dw2[u][0]=a[u]*pw2[1]%mod2;
	for(int i=1;i<=20;i++){
		anc[u][i]=anc[anc[u][i-1]][i-1];
		up1[u][i]=up1[u][i-1]+up1[anc[u][i-1]][i-1]*pw1[_2[i-1]];
		dw1[u][i]=dw1[u][i-1]*pw1[_2[i-1]]+dw1[anc[u][i-1]][i-1];
		up2[u][i]=(up2[u][i-1]+up2[anc[u][i-1]][i-1]*pw2[_2[i-1]])%mod2;
		dw2[u][i]=(dw2[u][i-1]*pw2[_2[i-1]]+dw2[anc[u][i-1]][i-1])%mod2;
	}
	for(int v:e[u]){
		if(v==fa){
			continue;
		}
		dfs(v,u);
	}
}
il int lca(int u,int v){
	if(dep[u]<dep[v]){
		swap(u,v);
	}
	int ddep=dep[u]-dep[v],tmp=0;
	while(ddep){
		if(ddep&1){
			u=anc[u][tmp];
		}
		ddep>>=1,tmp++;
	}
	if(u==v){
		return u;
	}
	for(int i=20;~i;i--){
		if(anc[u][i]!=anc[v][i]){
			u=anc[u][i],v=anc[v][i];
		}
	}
	return anc[u][0];
}
il int ganc(int u,int k){
	int tmp=0;
	while(k){
		if(k&1){
			u=anc[u][tmp];
		}
		k>>=1,tmp++;
	}
	return u;
}
il ull gha1(int u,int v,int rt,int len){
//	cout<<u<<" "<<v<<"\n";
	if(len<=dep[u]-dep[rt]+1){
		int tmp=0,cur=0;
		ull res=0;
		while(len){
			if(len&1){
				res+=up1[u][tmp]*pw1[cur];
				cur+=_2[tmp],u=anc[u][tmp];
			}
			len>>=1,tmp++;
		}
//		cout<<res<<"\n";
		return res;
	}
	int ddep=dep[u]-dep[rt]+1;
	int tmp=0,cur=0;
	ull res=0;
	len-=ddep;
	int tdep=ddep;
	while(ddep){
		if(ddep&1){
			res+=up1[u][tmp]*pw1[cur];
			cur+=_2[tmp],u=anc[u][tmp];
		}
		ddep>>=1,tmp++;
	}
	v=ganc(v,dep[v]-dep[rt]-len);
//	cout<<v<<" "<<res<<"\n";
	tmp=cur=0;
	int tlen=len;
	while(len){
		if(len&1){
			res+=dw1[v][tmp]*pw1[tdep+tlen-cur-_2[tmp]];
			cur+=_2[tmp],v=anc[v][tmp];
		}
		len>>=1,tmp++;
	}
//	cout<<res<<"\n";
	return res;
}
il ll gha2(int u,int v,int rt,int len){
	if(len<=dep[u]-dep[rt]+1){
		int tmp=0,cur=0;
		ll res=0;
		while(len){
			if(len&1){
				(res+=up2[u][tmp]*pw2[cur])%=mod2;
				cur+=_2[tmp],u=anc[u][tmp];
			}
			len>>=1,tmp++;
		}
		return res;
	}
	int ddep=dep[u]-dep[rt]+1;
	int tmp=0,cur=0;
	ll res=0;
	len-=ddep;
	int tdep=ddep;
	while(ddep){
		if(ddep&1){
			(res+=up2[u][tmp]*pw2[cur])%=mod2;
			cur+=_2[tmp],u=anc[u][tmp];
		}
		ddep>>=1,tmp++;
	}
	v=ganc(v,dep[v]-dep[rt]-len);
	tmp=cur=0;
	int tlen=len;
	while(len){
		if(len&1){
			(res+=dw2[v][tmp]*pw2[tdep+tlen-cur-_2[tmp]])%=mod2;
			cur+=_2[tmp],v=anc[v][tmp];
		}
		len>>=1,tmp++;
	}
	return res;
}
namespace cplx{
	bool end;
	il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m>>T;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1,u,v;i<n;i++){
		cin>>u>>v;
		e[u].pb(v),e[v].pb(u);
	}
	while(m--){
		int opt;
		cin>>opt;
		if(opt==1){
			int u1,v1,u2,v2;
			cin>>u1>>v1>>u2>>v2;
			wt[++q]=(wnti){u1,v1,u2,v2};
		}
		else{
			int u,w;
			cin>>u>>w;
			a[++n]=w;
			e[u].pb(n),e[n].pb(u);
		}
	}
	pw1[0]=pw2[0]=1;
	for(int i=1;i<=n;i++){
		pw1[i]=pw1[i-1]*bas1;
		pw2[i]=pw2[i-1]*bas2%mod2;
		tar1[i]=tar1[i-1]+i*pw1[i];
		tar2[i]=(tar2[i-1]+i*pw2[i])%mod2;
	}
	_2[0]=1;
	for(int i=1;i<=20;i++){
		_2[i]=_2[i-1]<<1;
	}
	dfs(1,0);
//	for(int u=1;u<=n;u++){
//		for(int i=0;i<=2;i++){
//			cout<<anc[u][i]<<" ";
//		}
//		puts("");
//	}
	for(int i=1,u1,v1,u2,v2,rt1,rt2,l,r;i<=q;i++){
		u1=wt[i].u1,v1=wt[i].v1;
		u2=wt[i].u2,v2=wt[i].v2;
		rt1=lca(u1,v1),rt2=lca(u2,v2);
		l=0;
		r=min(dep[u1]+dep[v1]-2*dep[rt1],dep[u2]+dep[v2]-2*dep[rt2])+1;
//		cout<<l<<" "<<r<<"\n";
		while(l<r){
			int mid=(l+r+1)>>1;
//			cout<<l<<" "<<r<<" "<<mid<<"\n";
			if(gha1(u2,v2,rt2,mid)-gha1(u1,v1,rt1,mid)==tar1[mid]&&(gha2(u2,v2,rt2,mid)-gha2(u1,v1,rt1,mid)+mod2)%mod2==tar2[mid]){
				l=mid;
			}
			else{
				r=mid-1;
			}
		}
		cout<<l<<"\n";
	}
	return 0;
}
}
int main(){return asbt::main();}
posted @ 2025-02-09 18:09  zhangxy__hp  阅读(22)  评论(0)    收藏  举报