给你一颗模板树,一颗大树初始等于模板树
先有一堆操作表示把模板树中以 u u 为根的子树复制一下接到大树的第 y y 号节点上
然后进行重新标号,新节点的编号 = = 大树原总结点数 + + 这个节点在模板树那颗子树里的排名
然后一堆询问.问大树上两个节点的距离
一道十分毒瘤并且不好实现的代码题
我们把大树上的每一整块缩成一个点,这样大树的点数就是线性的了(下面的图都是样例)
我们可以预处理两个块根节点之间的信息,然后其他的信息可以在原树中得到
我们先考虑一个问题,就是如何把大树中的点的编号转化成原树中的点的编号
可以发现我们只要记录一下所有块的起始编号,记为数组 begin b e g i n
因为 begin b e g i n 是递增的,所以我们可以二分求出这个点属于哪个块了
我们用大树中这个点的标号 − − 这个块起始的编号 +1 + 1 就是这个点在原子树中的排名了
e.g. e . g . 样例 begin b e g i n 数组是 1 6 9 1 6 9
假设询问 7 7 ,二分可以得到这个点属于 1 1 号块
这个点的排名就是 7−begin1+1=2 7 − b e g i n 1 + 1 = 2
在原树中以 4 4 为根的子树排名为 2 2 的点就是 4 4
所以我们就需要用主席树来实现求树上第 k k 大了(窝是按照二进制位来写的)
考虑一下怎么维护两个块根节点之间的距离
就是 dep[y d e p [ y 在原树中所代表的点 ]−dep[y ] − d e p [ y 所属的块的根节点在原树中代表的点 ]+1 ] + 1
所以我们还要记录一个东西, from f r o m 表示 y y 在原树中所代表的点
然后我们在对这棵缩点后的树 dfs d f s 预处理长度信息
假设询问 dis(x,y), d i s ( x , y ) , 设 belong(x)=u,belong(y)=v,w=lca(u,v) b e l o n g ( x ) = u , b e l o n g ( y ) = v , w = l c a ( u , v )
1. 1. 如果询问的两个点在同一个块里,那么可以直接在原树中查询了
2. 2. 如果两点不在同一个块里,主要的想法就是把他们都跳到 w w 块里,然后再在原树上查询
只考虑其中一个点 x x ,另一个点类似
①: u=w, u = w , 那么可以直接令 u=id(x) u = i d ( x ) ,然后返回了
②: u≠w, u ≠ w , 我们找到 w→u w → u 中的第一个点 z z ,我们处理 x→u→z→fromz x → u → z → f r o m z 的距离,然后令 u=fromz u = f r o m z 即可
x→u x → u 的距离就是原树中 dis(id(x),root[u]) d i s ( i d ( x ) , r o o t [ u ] )
u→z u → z 的距离是建树时 dfs d f s 可以预处理出来的
z→fromz z → f r o m z 的距离就是 1 1
给几张图理解一下
对于 y y 做同样的处理,最后 ans+= a n s + = 原树中 dis(u,v) d i s ( u , v ) 就可以了
#include
#define fp(i,a,b) for(register int i=a,I=b+1;i
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
char c;T y=1;while(c=gc(),(c<48||571)if(c==45)y=-1;x=c-48;
while(c=gc(),4758)x=x*10+c-48;x*=y;
}
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+5,M=2e5+5;
typedef int arr[N];
typedef long long ll;
struct eg{int nx,to;};
struct Pt{int sz;Pt*ch[2];};
int n,m,q;
struct Real{
int dft,H;arr fi,fa,sz,son,top,dep,lef,rig;
Pt tr[N*20],*pt,*T[N];eg e[M];
inline Pt*ins(Pt*B,const int x){
Pt*A=++pt,*tp=A;int d;
fd(i,H,0){d=(x>>i)&1;
A->sz=B->sz+1;
A->ch[!d]=B->ch[!d];
A=A->ch[d]=++pt;B=B->ch[d];
}A->sz=B->sz+1;
return tp;
}
void dfs(int u){
dep[u]=dep[fa[u]]+(sz[u]=1);
go(u)if(v^fa[u]){
fa[v]=u;dfs(v);sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void dfs(int u,int t){
lef[u]=++dft;T[dft]=ins(T[dft-1],u);
top[u]=t;if(son[u])dfs(son[u],t);
go(u)if(v^fa[u]&&v^son[u])dfs(v,v);rig[u]=dft;
}
inline int lca(int u,int v){
for(;top[u]^top[v];dep[top[u]]>dep[top[v]]?u=fa[top[u]]:v=fa[top[v]]);
return dep[u]inline int dis(int u,int v){return dep[u]+dep[v]-(dep[lca(u,v)]<<1);}
inline void add(int u,int v){static int ce=0;e[++ce]={fi[u],v},fi[u]=ce;}
inline void init(){
int u,v;H=log2(n)+1;pt=tr;
*(T[0]=tr)=(Pt){0,tr,tr};
fp(i,2,n)sd(u),sd(v),add(u,v),add(v,u);
dfs(1),dfs(1,1);
}
inline int qry(int u,int k){
Pt*A=T[lef[u]-1],*B=T[rig[u]];int sp,tp=0;
fd(i,H,0){
sp=B->ch[0]->sz-A->ch[0]->sz;
if(k<=sp)A=A->ch[0],B=B->ch[0];
else k-=sp,tp|=1<ch[1],B=B->ch[1];
}return tp;
}
}t1;
struct Vitual{
eg e[N];int A;arr fi,fa,rt,sz,dep,son,top,from;ll len[N],bg[N];
void dfs(int u){
dep[u]=dep[fa[u]]+(sz[u]=1);
go(u){
dfs(v);sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void dfs(int u,int t){
top[u]=t;if(son[u])dfs(son[u],t);
go(u)if(v^son[u])dfs(v,v);
}
inline int lca(int u,int v){
for(;top[u]^top[v];dep[top[u]]>dep[top[v]]?u=fa[top[u]]:v=fa[top[v]]);
return dep[u]inline int Go(int u,int f){
while(top[u]^top[f]){u=top[u];if(fa[u]==f)return u;u=fa[u];}
return son[f];
}
inline void add(int u,int v,int w){static int ce=0;e[++ce]={fi[u],v},fi[u]=ce;len[v]=len[u]+w;}
inline int bl(ll x){return upper_bound(bg,bg+A+1,x)-bg-1;}
inline int RealId(ll x){
if(x1])return x;
int b=bl(x),k=x-bg[b]+1;
if(rt[b]==1)return k;
return t1.qry(rt[b],k);
}
inline void sol(){
ll Cnt=n,y;bg[0]=rt[0]=1;
fp(i,1,m){
A=i;sd(rt[i]),sd(y);
bg[i]=Cnt+1;Cnt+=t1.sz[rt[i]];
from[i]=RealId(y);fa[i]=bl(y);
add(fa[i],i,t1.dep[from[i]]-t1.dep[rt[fa[i]]]+1);
}dfs(0),dfs(0,0);
ll x,ans=0;int u,v,w;
while(q--){
sd(x),sd(y);u=bl(x),v=bl(y);
if(u==v){we(t1.dis(RealId(x),RealId(y)));continue;}
w=lca(u,v);ans=0;
if(u^w){
int _=Go(u,w);
ans+=len[u]-len[_]+1+t1.dep[RealId(x)]-t1.dep[rt[u]];
u=from[_];
}else u=RealId(x);
if(v^w){
int _=Go(v,w);
ans+=len[v]-len[_]+1+t1.dep[RealId(y)]-t1.dep[rt[v]];
v=from[_];
}else v=RealId(y);
ans+=t1.dis(u,v);
we(ans);
}
}
}t2;
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
sd(n),sd(m),sd(q);
t1.init();t2.sol();
return Ot(),0;
}