luogu P3248 [HNOI2016]树
题面传送门
不得不说这个正解是真的暴力本来还想写可持久化平衡树的(
考虑我们将每个新加入的树看作一个点。
那么我们要支持这些操作:
查询一个点在那个树里面,这个直接lowerbound就好了。
查询一颗树内某个点在原树哪个节点,这个直接把原树的dfs序拍了然后主席树区间\(k\)大就好了。
查询现在树上两个同一棵树的节点距离,这个直接找到在原树上哪个节点然后倍增就好了。
那么在中间新树上倍增,两端和lca处到原树上倍增就好了。
时间复杂度大常数\(O(nlogn)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 100000
#define mod 998244353
#define eps (1e-5)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
using namespace std;
int n,m,Q,lg[N+5],bg[N+5],siz[N+5],Fr[N+5];ll x,y,z,st[N+5],en[N+5];
struct yyy{int to,z;};I void swap(int &x,int &y){x^=y^=x^=y;}
struct ljb{int head,h[N+5];yyy f[N+5<<1];I void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}};
struct Tree1{
ljb s;int fa[N+5][20],root[N+5],d[N+5],dfn[N+5],dh,L[N+5<<5],R[N+5<<5],F[N+5<<5],cnt;
I void memcpy(int x,int y){R[y]=R[x];L[y]=L[x];F[y]=F[x];}
I void insert(int x,int &now,int l=1,int r=n){memcpy(now,++cnt);now=cnt;F[now]++;if(l==r) return;int m=l+r>>1;x<=m?insert(x,L[now],l,m):insert(x,R[now],m+1,r);}
I int Query(int x,int y,int z,int l=1,int r=n){int m;x=root[x-1];y=root[y];while(l^r) m=l+r>>1,z<=F[L[y]]-F[L[x]]?(y=L[y],x=L[x],r=m):(z-=F[L[y]]-F[L[x]],y=R[y],x=R[x],l=m+1);return l;}
I void dfs(int x,int last){dfn[bg[x]=++dh]=x;siz[x]=1;d[x]=d[last]+1;fa[x][0]=last;int i;yyy tmp;for(i=1;fa[x][i-1];i++) fa[x][i]=fa[fa[x][i-1]][i-1];for(i=s.h[x];i;i=tmp.z) tmp=s.f[i],tmp.to^last&&(dfs(tmp.to,x),siz[x]+=siz[tmp.to]);}
I int dist(int x,int y){d[x]<d[y]&&(swap(x,y),0);int Ans=d[x]-d[y];while(d[x]^d[y]) x=fa[x][lg[d[x]-d[y]]];if(x==y) return Ans;for(int i=lg[d[x]];~i;i--) fa[x][i]&&fa[y][i]&&fa[x][i]^fa[y][i]&&(x=fa[x][i],y=fa[y][i],Ans+=2<<i);return Ans+2;}
I void Make(){re int i;for(i=1;i<n;i++) scanf("%lld%lld",&x,&y),s.add(x,y),s.add(y,x);dfs(1,0);for(i=1;i<=n;i++) root[i]=root[i-1],insert(dfn[i],root[i]);}
I int FindId(ll x,int id){return Query(bg[Fr[id]],bg[Fr[id]]+siz[Fr[id]]-1,x-st[id]+1);}
}T1;
struct Tree2{
int fa[N+5][20],d[N+5],nx,ny,lcas;ll cnt,To[N+5],W[N+5];ljb s;
I void dfs(int x,int last){yyy tmp;int i;d[x]=d[last]+1;W[x]+=W[last];for(i=1;fa[x][i-1];i++) fa[x][i]=fa[fa[x][i-1]][i-1];for(i=s.h[x];i;i=tmp.z) tmp=s.f[i],dfs(tmp.to,x);}
I int lca(int x,int y){d[x]<d[y]&&(swap(x,y),0);while(d[x]^d[y]) x=fa[x][lg[d[x]-d[y]]];if(x==y) return x;for(int i=lg[d[x]];~i;i--) fa[x][i]&&fa[y][i]&&fa[x][i]^fa[y][i]&&(x=fa[x][i],y=fa[y][i]);return fa[x][0];}
I int kth(int x,int k){while(k) x=fa[x][lg[k&-k]],k-=k&-k;return x;}
I ll dist(ll x,ll y){
nx=lower_bound(en+1,en+m,x)-en;ny=lower_bound(en+1,en+m,y)-en;d[nx]<d[ny]&&(swap(nx,ny),swap(x,y),0);lcas=lca(nx,ny);if(nx==ny) return T1.dist(T1.FindId(x,nx),T1.FindId(y,ny));ll Ans=0;
if(lcas==ny){Ans=T1.dist(Fr[nx],T1.FindId(x,nx))+1+W[nx];x=kth(nx,d[nx]-d[lcas]-1);Ans-=W[x];return Ans+dist(T1.FindId(To[x],ny),T1.FindId(y,ny));}
Ans=T1.dist(Fr[nx],T1.FindId(x,nx))+T1.dist(Fr[ny],T1.FindId(y,ny))+2+W[nx]+W[ny];x=kth(nx,d[nx]-d[lcas]-1);y=kth(ny,d[ny]-d[lcas]-1);Ans-=W[x]+W[y];return Ans+T1.dist(T1.FindId(To[x],lcas),T1.FindId(To[y],lcas));
}
I void Make(){
re int i;st[1]=1;cnt=en[1]=n;Fr[1]=1;m++;for(i=2;i<=m;i++) scanf("%d%lld",&Fr[i],&To[i]),st[i]=cnt+1,cnt+=siz[Fr[i]],en[i]=cnt,fa[i][0]=z=lower_bound(en+1,en+i,To[i])-en,s.add(z,i),W[i]=T1.dist(Fr[z],T1.FindId(To[i],z))+1;
dfs(1,0);while(Q--) scanf("%lld%lld",&x,&y),printf("%lld\n",dist(x,y));
}
}T2;
int main(){
freopen("1.in","r",stdin);freopen("1.out","w",stdout);
re int i;scanf("%d%d%d",&n,&m,&Q);for(i=2;i<=max(n,m);i++)lg[i]=lg[i/2]+1;T1.Make();T2.Make();
}