题目大意:给你$m$棵由$n$个点构成的全等的树$A$。这$m$棵树之间有$m-1$条边相连,组成了一棵大树。
有$q$组询问,每次询问这棵大树上两点之间的距离。
$n,m,q≤10^5$
这是一道小视野双倍经验题
这一题有一种显然的虚树做法,这种做法我之前打过了,这次换一种做法。
如果询问所在两点在同一棵小树内,那么显然直接倍增就可以了。
我们将连接$m$棵树的边抽出来,构成另外一棵树(暂且称作树$B$),节点$p$表示第$p$棵树,我们钦定这棵树的$1$号点为根。
我们令$up1[i]$表示树$B$中,连接$i$号点$father$所在的边,它在第$i$棵小树中所连接的节点。
令$up2[i]$表示树$B$中,连接$i$号点$father$所在的边,它在第$fa[i]$棵小树中所连接的点。
令$dis[i]$表示从树$B$的第$1$号树的$1$号节点开始,到达小树$i$第$up1[i]$号节点的距离。
对于一组询问$(w,x,y,z)$,我们求出$w,y$的$lca$,令$w'$表示在$w$到$lca$的路径上,离$lca$最近的点(不包括$lca$本身),同理求出$y'$。
设最终答案为$ans$
若存在$w'$,则$ans+=A.dis(x,up1[x])+dis[w]-dis[w']$,并令$x=up2[w']$。
若存在$y'$,则$ans+=A.dis(z,up1[z])+dis[y]-dis[y']$,并令$z=up2[y']$。
最后$ans+=A.dis(x,z)$即可。
注意细节
1 #include<bits/stdc++.h> 2 #define M 100005 3 #define L long long 4 using namespace std; 5 int n,m,q; 6 struct tree1{ 7 struct edge{int u,next;}e[M*2]; int head[M],use=0; 8 void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;} 9 int f[M][20],dep[M]; 10 void dfs(int x,int fa){ 11 f[x][0]=fa; dep[x]=dep[fa]+1; 12 for(int i=1;i<20;i++) f[x][i]=f[f[x][i-1]][i-1]; 13 for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa) dfs(e[i].u,x); 14 } 15 int getlca(int x,int y){ 16 if(dep[x]<dep[y]) swap(x,y); int cha=dep[x]-dep[y]; 17 for(int i=19;~i;i--) if((1<<i)&cha) x=f[x][i]; 18 for(int i=19;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; 19 if(x==y) return x; return f[x][0]; 20 } 21 int getdis(int x,int y){ 22 int lca=getlca(x,y); 23 return dep[x]+dep[y]-2*dep[lca]; 24 } 25 void init(){ 26 for(int i=1;i<n;i++){ 27 int x,y; scanf("%d%d",&x,&y); 28 add(x,y); add(y,x); 29 } 30 dfs(1,0); 31 } 32 }a; 33 struct tree2{ 34 struct edge{int u,us,ut,next;}e[M*2]; int head[M],use=0; 35 void add(int x,int y,int us,int ut){use++;e[use].u=y;e[use].us=us;e[use].ut=ut;e[use].next=head[x];head[x]=use;} 36 int f[M][20],dep[M],up1[M],up2[M]; L dis[M]; 37 void dfs(int x,int fa){ 38 f[x][0]=fa; dep[x]=dep[fa]+1; 39 for(int i=1;i<20;i++) f[x][i]=f[f[x][i-1]][i-1]; 40 for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){ 41 up1[e[i].u]=e[i].ut; up2[e[i].u]=e[i].us; 42 dis[e[i].u]=dis[x]+a.getdis(up1[x],e[i].us)+1; 43 dfs(e[i].u,x); 44 } 45 } 46 int getlca(int x,int y){ 47 if(dep[x]<dep[y]) swap(x,y); int cha=dep[x]-dep[y]; 48 for(int i=19;~i;i--) if((1<<i)&cha) x=f[x][i]; 49 for(int i=19;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; 50 if(x==y) return x; return f[x][0]; 51 } 52 int jump(int x,int k){ 53 for(int i=19;~i;i--) if((1<<i)&k) x=f[x][i]; 54 return x; 55 } 56 void init(){ 57 for(int i=1;i<m;i++){ 58 int x,X,y,Y; scanf("%d%d%d%d",&x,&X,&y,&Y); 59 add(x,y,X,Y); add(y,x,Y,X); 60 } 61 dfs(1,0); 62 } 63 }b; 64 int main(){ 65 scanf("%d%d%d",&n,&m,&q); 66 a.init(); 67 b.init(); 68 while(q--){ 69 int x,X,y,Y; scanf("%d%d%d%d",&x,&X,&y,&Y); 70 int lca=b.getlca(x,y); 71 L ans=0; 72 if(x!=lca){ 73 ans+=a.getdis(X,b.up1[x]); 74 int xx=b.jump(x,b.dep[x]-b.dep[lca]-1); 75 ans+=b.dis[x]-b.dis[xx]+1; 76 X=b.up2[xx]; 77 } 78 if(y!=lca){ 79 ans+=a.getdis(Y,b.up1[y]); 80 int yy=b.jump(y,b.dep[y]-b.dep[lca]-1); 81 ans+=b.dis[y]-b.dis[yy]+1; 82 Y=b.up2[yy]; 83 } 84 ans+=a.getdis(X,Y); 85 printf("%lld\n",ans); 86 } 87 }