【题解】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();}

浙公网安备 33010602011771号