题目大意
有一棵(n)个点的树,根为1号点,称它为“模板树”。
有一棵初始和模板树相同的树,称它为“当前树”。
对“当前树”有(m)次操作,每次操作给出两个数(x,y)表示将模板树中(x)及其子树复制下来并粘贴到模板树,该子树的根与点(y)连边,假设操作前“当前树”有(a)个点,“模板树”中(x)的子树大小为(b),则粘贴上去的(b)个点的标号按这棵子树在“模板树”中的标号从小到大的顺序依次标为(a+1,a+2,...,a+b)。
(m)次操作后,有(q)次询问,每次问“当前树”上两点间的距离。
(n,m,qleq 10^5;)
题解
建另一棵树:对于每次操作,粘贴过去的子树的根向点(y)所在的树的“根”连边(如果点(y)是之前的某一次粘贴过去的点,那么它的“根”是粘贴过去时子树的根,而不是整棵树的根)。
询问两点距离时分类讨论它们是不是同一次粘贴过去的。如果是就直接在模板树上求,如果不是就让它们分别走到和它们同一次粘贴过去的子树的根,再在新树中求LCA。
代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 100007
#define maxnd 2000007
#define LL long long
#define pll pair<LL,LL>
#define fi first
#define se second
#define mp make_pair
#define ls ch[u][0]
#define rs ch[u][1]
#define mi ((l+r)>>1)
using namespace std;
LL read()
{
LL x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(LL x)
{
if(x==0){putchar('0'),putchar('
');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('
');
return;
}
struct nd{LL fa,start;int bac;}ad[maxn];
LL nowsiz,qu[maxn],qv[maxn],dis[maxn][20];
vector<pll>qx[maxn];
int rt[maxn],ch[maxnd][2],num[maxnd],siz[maxn],cntnd,cntad,cnte,dep2[maxn];
int n,m,q,fir[maxn],nxt[maxn<<1],v[maxn<<1],st[20][maxn<<1],tim,dfn[maxn],lg[maxn<<1],dep[maxn],anc[maxn][20];
map<LL,int>to;
void ade(int u1,int v1){v[cnte]=v1,nxt[cnte]=fir[u1],fir[u1]=cnte++;}
void getdfn(int u)
{
st[0][++tim]=u,dfn[u]=tim,siz[u]=1;
view(u,k)if(!dep[v[k]]&&v[k]!=1){dep[v[k]]=dep[u]+1,getdfn(v[k]),siz[u]+=siz[v[k]],st[0][++tim]=u;}
}
inline int lca(int x,int y)
{
x=dfn[x],y=dfn[y];if(x>y)swap(x,y);
int len=y-x+1;return dep[st[lg[len]][x]]<dep[st[lg[len]][y-(1<<lg[len])+1]]?st[lg[len]][x]:st[lg[len]][y-(1<<lg[len])+1];
}
inline int Dis(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
int getid(LL x)
{
int L=1,R=m+1,res=-1;
while(L<=R)
{
int mid=(L+R)>>1;
if(ad[mid].start<=x)res=max(res,mid),L=mid+1;
else R=mid-1;
}
return res;
}
inline void pu(int u){num[u]=0;if(ls)num[u]+=num[ls];if(rs)num[u]+=num[rs];return;}
int build(int l,int r,int x)
{
int u=++cntnd;
if(x<=l&&r<=x){num[u]=1;return u;}
if(x<=mi)ls=build(l,mi,x);
else rs=build(mi+1,r,x);
num[u]=1;return u;
}
int merge(int u,int ub,int l,int r)
{
if(!u||!ub){return u|ub;}
ls=merge(ls,ch[ub][0],l,mi);
rs=merge(rs,ch[ub][1],mi+1,r);
pu(u);return u;
}
int ask(int u,int l,int r,int x)
{
if(l==r)return l;
if(!ls||num[ls]<x){x-=ls?num[ls]:0;return ask(rs,mi+1,r,x);}
return ask(ls,l,mi,x);
}
void getto(int u)
{
rt[u]=build(1,n,u);
view(u,k)if(dep[v[k]]>dep[u]){getto(v[k]),rt[u]=merge(rt[u],rt[v[k]],1,n);}
int li=qx[u].size()-1;
rep(i,0,li){to[qx[u][i].fi]=ask(rt[u],1,n,qx[u][i].se);}
}
int main()
{
n=read(),m=read(),q=read();
rep(i,1,n)fir[i]=-1;
rep(i,2,n){int x=read(),y=read();ade(x,y),ade(y,x);}
getdfn(1);lg[0]=-1;
rep(i,1,tim)lg[i]=lg[i>>1]+1;
rep(i,1,lg[tim])for(int j=1;j+(1<<i)-1<=tim;j++)
st[i][j]=dep[st[i-1][j]]<dep[st[i-1][j+(1<<(i-1))]]?st[i-1][j]:st[i-1][j+(1<<(i-1))];
ad[1].bac=1,ad[1].fa=0,ad[1].start=1,nowsiz=n;
rep(i,2,m+1)
{
int a=read();LL b=read();
ad[i].bac=a,ad[i].fa=b,ad[i].start=nowsiz+1,nowsiz+=siz[a];//cout<<siz[a]<<" "<<a<<endl;
}cntad=m;
rep(i,2,m+1){int id=getid(ad[i].fa);anc[i][0]=id;qx[ad[id].bac].push_back(mp(ad[i].fa,ad[i].fa-ad[id].start+1));}
rep(i,1,q)
{
qu[i]=read(),qv[i]=read();int idu=getid(qu[i]),idv=getid(qv[i]);
qx[ad[idu].bac].push_back(mp(qu[i],qu[i]-ad[idu].start+1)),
qx[ad[idv].bac].push_back(mp(qv[i],qv[i]-ad[idv].start+1));
}
getto(1);
rep(i,2,m+1)
{
dis[i][0]=Dis(ad[anc[i][0]].bac,to[ad[i].fa])+1,dep2[i]=dep2[anc[i][0]]+1;
rep(j,1,19)
{
anc[i][j]=anc[anc[i][j-1]][j-1];
dis[i][j]=dis[i][j-1]+dis[anc[i][j-1]][j-1];
}
}
rep(i,1,q)
{
LL ans=0,x=qu[i],y=qv[i],idx=getid(x),idy=getid(y);
if(idx==idy){ans=Dis(to[x],to[y]);}
else
{
if(dep2[idx]<dep2[idy])swap(idx,idy),swap(x,y);
dwn(i,19,0)if(anc[idx][i]&&dep2[anc[idx][i]]>dep2[idy])
{
if(x&&to[x]!=ad[idx].bac)ans+=Dis(to[x],ad[idx].bac);
ans+=dis[idx][i],idx=anc[idx][i],x=0;
}
if(anc[idx][0]==idy)
{
if(x&&to[x]!=ad[idx].bac)ans+=Dis(to[x],ad[idx].bac);x=0;
ans+=Dis(to[ad[idx].fa],to[y])+1;
}
else
{
if(dep2[idx]>dep2[idy])
{
if(x&&to[x]!=ad[idx].bac)ans+=Dis(to[x],ad[idx].bac);
ans+=dis[idx][0],idx=anc[idx][0],x=0;
}
dwn(i,19,0)if(anc[idx][i]&&anc[idy][i]&&anc[idx][i]!=anc[idy][i])
{
if(x&&to[x]!=ad[idx].bac)ans+=Dis(to[x],ad[idx].bac);
if(y&&to[y]!=ad[idy].bac)ans+=Dis(to[y],ad[idy].bac);
ans+=dis[idx][i]+dis[idy][i],idx=anc[idx][i],idy=anc[idy][i];x=0,y=0;
}
if(x&&to[x]!=ad[idx].bac)ans+=Dis(to[x],ad[idx].bac);
if(y&&to[y]!=ad[idy].bac)ans+=Dis(to[y],ad[idy].bac);
ans+=Dis(to[ad[idx].fa],to[ad[idy].fa])+2;
}
}
write(ans);
}
return 0;
}