其实思想特别简单,首先我们是不可能真的把一颗子树全部弄过去的,所以只能把一个根节点代表一个子树连入新的树中。
1.如何找到新树节点对应的原树节点编号。
对于原来的模板树用主席树维护dfs序,每次先二分出这个节点在哪一次操作是添加的,找到原来的子树根节点,然后用主席树查找区间第k大就好了。
2.新树求距离
两种情况,要么在同一次添加的,直接在原树上做,否则倍增到新树的lca上,计算得到。
虽然思想简单,但是写起来的话。。。坑
1.判断两个点是不是祖孙关系,特殊处理
2.每一次先倍增到同一个块,然后在块上倍增
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxn 100021
#define LL long long
using namespace std;
int n,m,qq,cur[maxn],in[maxn],out[maxn],ca[maxn];
int head[maxn],tot=1,cnt,f[maxn][20],rt[maxn],size_tr,size[maxn];
LL h[maxn],g[maxn][20],ss[maxn];
int ls[maxn*40],rs[maxn*40],sum[maxn*40];
struct edge{int v,next;}e[maxn*2];
void adde(int a,int b){e[tot].v=b,e[tot].next=head[a];head[a]=tot++;}
void dfs(int u,int fa){
cur[in[u]=++cnt]=u,f[u][0]=fa,h[u]=h[fa]+1,size[u]=1;
for(int i=1;i<=17;i++)f[u][i]=f[f[u][i-1]][i-1];
for(int v,i=head[u];i;i=e[i].next){
if((v=e[i].v)==fa)continue;
dfs(v,u);size[u]+=size[v];
}out[u]=cnt;
}
/**************主席树查询第k大***************/
void insert(int x,int& y,int l,int r,int id){
y=++size_tr;ls[y]=ls[x],rs[y]=rs[x],sum[y]=sum[x]+1;
if(l==r)return;
int mid=l+r>>1;
if(id>mid)insert(rs[x],rs[y],mid+1,r,id);
else insert(ls[x],ls[y],l,mid,id);
}
int query(int x,int y,int l,int r,int k){
if(l==r)return l;
int mid=l+r>>1;
int s=sum[ls[y]]-sum[ls[x]];
if(s>=k)return query(ls[x],ls[y],l,mid,k);
else return query(rs[x],rs[y],mid+1,r,k-s);
}
//新树的处理
int nn,nf[maxn][20],fl[maxn],nd[maxn];
LL nh[maxn];
int find(LL x){//二分查找现在的编号在哪一个节点
int l=0,r=nn;
while(l<r){
int mid=l+r+1>>1;
if(ss[mid]>=x)r=mid-1;
else l=mid;
}
return l+1;
}
int Q(LL x,int nx){//查询现在的编号对应的原来的编号
x-=ss[nx-1];
return query(rt[in[ca[nx]]-1],rt[out[ca[nx]]],1,n,x);
}
void init(int a,LL b){
nn++;ca[nn]=a;ss[nn]=ss[nn-1]+size[a];
int B=find(b),lb=Q(b,B);fl[nn]=lb;
nf[nn][0]=B;nh[nn]=nh[B]+(LL)h[lb]-h[ca[B]]+1;
nd[nn]=nd[B]+1;
for(int i=1;i<=17;i++)nf[nn][i]=nf[nf[nn][i-1]][i-1];
}
void build(){
int a;LL b;ca[++nn]=1;ss[nn]=size[1];nh[nn]=nd[nn]=1;
while(m--){
scanf("%d%lld",&a,&b);
init(a,b);
}
}
int lca1(int a,int b){
if(h[a]>h[b])swap(a,b);
for(int i=17;i>=0;i--)if(h[f[b][i]]>=h[a])b=f[b][i];
if(a==b)return a;
for(int i=17;i>=0;i--){
if(f[a][i]==f[b][i])continue;
a=f[a][i],b=f[b][i];
}return f[a][0];
}
int lca2(int a,int b){
if(nd[a]>nd[b])swap(a,b);
for(int i=17;i>=0;i--)if(nd[nf[b][i]]>=nd[a])b=nf[b][i];
if(a==b)return a;
for(int i=17;i>=0;i--){
if(nf[a][i]==nf[b][i])continue;
a=nf[a][i],b=nf[b][i];
}return nf[a][0];
}
void solve(){
LL a,b;int x,y,dx,la,lb,dy;
while(qq--){
scanf("%lld%lld",&a,&b);
x=find(a),y=find(b);//大树的编号
la=Q(a,x),lb=Q(b,y);//原来编号
if(x==y){
int g=lca1(la,lb);
printf("%d\n",h[la]+h[lb]-2*h[g]);
}else{
int g=lca2(x,y);bool ok=false;
dx=x,dy=y;
for(int i=17;i>=0;i--){
if(nd[nf[dx][i]]>nd[g])dx=nf[dx][i];
if(nd[nf[dy][i]]>nd[g])dy=nf[dy][i];
}
if(x==g)dx=la;else dx=fl[dx];
if(y==g)dy=lb;else dy=fl[dy];
int gg=lca1(dx,dy);
if(nh[x]>nh[y]){
swap(x,y),swap(la,lb);swap(dx,dy);
}
if(g==x&&la==gg)ok=true;
if(!ok)
printf("%lld\n",nh[x]+h[la]-h[ca[x]]+h[lb]-h[ca[y]]+nh[y]-2*(nh[g]+h[gg]-h[ca[g]]));
else printf("%lld\n",h[lb]-h[ca[y]]+nh[y]-(nh[x]+h[la]-h[ca[x]]));
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&qq);
for(int a,b,i=1;i<n;i++){
scanf("%d%d",&a,&b);
adde(a,b),adde(b,a);
}dfs(1,0);
for(int i=1;i<=n;i++)insert(rt[i-1],rt[i],1,n,cur[i]);
build();solve();
return 0;
}