问题描述
这天,小明在机房学习。他发现机房里一共有n台电脑,编号为1到n,电脑和电脑之间有网线连接,一共有n-1根网线将n台电脑连接起来使得任意两台电脑都直接或者间接地相连。小明发现每台电脑转发、发送、或者接受信息需要的时间取决于这台电脑和多少台电脑直接相连,而信息在网线中的传播时间可以忽略。比如如果是某台电脑用网线直接连接了另外d台电脑,那么任何经过这台电脑的信息都会延迟d单位时间(发送方和接收方也会产生这样的延迟,当然如果发送方和接收方都是同一台电脑就只会产生一次延迟)。
小明一共产生了m个疑问:如果电脑ui 向电脑vi发送信息,那么信息从ui传到vi的最短时间是多少?
输入格式
输入共n+m 行,第一行为两个正整数n,m。
后面n-1行,每行两个正整数x,y表示编号为x,y的两台电脑用网线直接相连
后面m 行,每行两个正整数ui,vi表示小明的第i 个疑问
输出格式
输出共m行,第i 行一个正整数表示小明第i 个疑问的答案
样例输入
4 3
1 2
1 3
2 4
2 3
3 4
3 3
样例输出
5
6
1
样例说明
这四台电脑各自的延迟分别为 2,2,1,1。
对于第一个询问,从2 到3 需要经过2,1,3,所以时间和为2+2+1=5 。
对于第二个询问,从3到4需要经过3,1,2,4,所以时间和为1+2+2+1=6。
对于第三个询问,从3到3 需只会产生一次延迟,所以时间为1。
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
//数组模拟链表所需数据,感觉vector<int>比这个好,至少不需要这么的(但是已经习惯了)
int e[N],ne[N],h[N],idx;
//dist[N]->记录某个点到总根这路径上总的延迟(度数) d[N]->某个点的入出度数
//depth[N]->记录某个点的高度 up[N][20]->表示某个点向上移动2的少次方的高度(LCA)
int dist[N],d[N],depth[N],up[N][20];
//构建图(模板)
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
//dfs()创建ST数组(换句人话就是创建一个预处理出所有点向上跳多少2的x次方能达到什么点)->LCA模板
void dfs(int ch,int pa){
depth[ch]=depth[pa]+1;
dist[ch]=d[ch]+dist[pa]; //总延迟=入出度数+父节点的延迟
up[ch][0]=pa;
for(int i=1;i<=19;i++){
up[ch][i]=up[up[ch][i-1]][i-1]; //往上跳2^i次方
}
for(int i=h[ch];i!=-1;i=ne[i]){
int j=e[i]; 依次遍历子节点
if(j==pa) continue;
dfs(j,ch);
}
}
//LCA模板(不知道可以先去学一下->不是很难)
int LCA(int a,int b){
//保证a是深度最大的那一个,这样代码要好写一点
if(depth[a]<depth[b]) swap(a,b);
//将a点跳到和b同等高度(至于为什么可以自己想一下->授之以鱼不如授之以渔)----->如果实在想不出可以在评论区call
for(int i=19;i>=0;i--){
if(depth[up[a][i]]>=depth[b]){
a=up[a][i];
}
}
//假如b就是最近公共祖宗节点,就提前跳出
if(a==b) return b;
//a,b点一起跳到公共节点的“下一层”------至于为什么可以准确的停在下一层,我给个提示
//二进制中任意一位都可以由他后面所有位相加再加1得到
for(int i=19;i>=0;i--)
{
if(up[a][i]!=up[b][i])
{
a=up[a][i],b=up[b][i];
}
}
//返回公共节点
return up[a][0];
}
int main(){
int n,m;
cin>>n>>m;
//构图模板
memset(h,-1,sizeof h); //以h的大小逐个拷贝-1
for(int i=0;i<n-1;i++){
int a,b;
cin>>a>>b;
add(a,b),add(b,a);
d[a]++,d[b]++;
}
//将一号点作为总根(其他点也我所谓)
dfs(1,0);
//LCA模板
while(m--){
int l,r;
cin>>l>>r;
int lca=LCA(l,r);
cout<<dist[l]+dist[r]-2*dist[lca]+d[lca]<<endl;
}
return 0;
}