2022蓝桥杯/机房/c\c++

问题描述

    这天,小明在机房学习。他发现机房里一共有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;
}

  • 17
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值