当前位置: 首页 > news >正文

第十三届蓝桥杯C++B组国赛H题——机房 (AC)

目录

  • 1.机房
    • 1.问题描述
    • 2.输入格式
    • 3.输出格式
    • 4.样例输入
    • 5.样例说明
    • 6.数据范围
    • 7.原题链接
  • 2.解题思路
  • 3.Ac_code
    • tarjan
    • 倍增LCA

1.机房

1.问题描述

这天, 小明在机房学习。

他发现机房里一共有 n n n 台电脑, 编号为 1 到 n n n, 电脑和电脑之间有网线连 接, 一共有 n − 1 n-1 n1 根网线将 n n n 台电脑连接起来使得任意两台电脑都直接或者间 接地相连。

小明发现每台电脑转发、发送或者接受信息需要的时间取决于这台电脑和 多少台电脑直接相连, 而信息在网线中的传播时间可以忽略。比如如果某台电脑 用网线直接连接了另外 d d d 台电脑, 那么任何经过这台电脑的信息都会延迟 d d d 单 位时间 (发送方和接收方也会产生这样的延迟, 当然如果发送方和接收方都是 同一台电脑就只会产生一次延迟)。

小明一共产生了 m m m 个疑问: 如果电脑 u i u_{i} ui 向电脑 v i v_{i} vi 发送信息, 那么信息从 u i u_{i} ui 传到 v i v_{i} vi 的最短时间是多少?

2.输入格式

输入共 n + m n+m n+m 行, 第一行为两个正整数 n , m n,m n,m

后面 n − 1 n−1 n1 行, 每行两个正整数 x , y x, y x,y 表示编号为 x x x y y y 的两台电脑用网线 直接相连。

后面 m m m 行, 每行两个正整数 u i , v i u_{i}, v_{i} ui,vi表示小明的第 i i i 个疑问。

3.输出格式

输出共 m m m 行, 第 i i i 行一个正整数表示小明第 i i i 个疑问的答案。

4.样例输入

4 3
1 2
1 3
2 4
2 3
3 4
3 3

5.样例说明

这四台电脑各自的延迟分别为 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 。

6.数据范围

n , m ≤ 100000 n,m≤100000 n,m100000

7.原题链接

机房

2.解题思路

还是一道比较明显的求LCA(最近公共祖先)模型的题目,我们可以使用多种方法来解决该问题,这里我们使用更好写的离线的tarjan算法来解决该问题 (已补充倍增做法)。

除去tarjan算法必用的基础数组,我们还有一个数组d[],d[i]记录的是每个点的出度,也就是它的延迟时间,以及数组w[],w[i]的含义是点i到根节点的延迟时间。在通过dfs求出每个点iw[i]以后,在tarjan中我们该如何求出两点的延迟时间呢?

我们设点ij的延迟时间为 f ( i , j ) f(i,j) f(i,j),当我们求得ij的最近公共祖先为anc,我们首先让 f ( i , j ) = w [ i ] + w [ j ] f(i,j)=w[i]+w[j] f(i,j)=w[i]+w[j],但很明显,我们多加了两遍 w [ a n c ] w[anc] w[anc],所以我们需要减去两倍的 w [ a n c ] w[anc] w[anc],但延迟时间还包括经过anc的时间,所以还得加上一个 d [ a n c ] d[anc] d[anc]此处请结合w[]d[]的含义理解。
最后能得出式子: f ( i , j ) = w [ i ] + w [ h ] − w [ a n c ] ∗ 2 + d [ a n c ] f(i,j)=w[i]+w[h]-w[anc]*2+d[anc] f(i,j)=w[i]+w[h]w[anc]2+d[anc]在这里插入图片描述

 假设图中当求DE的延迟时间,根据数组定义我们可知 w [ D ] w[D] w[D] [ A , B , C , D ] [A,B,C,D] [A,B,C,D]四点的延迟时间之和。 w [ E ] w[E] w[E] [ E , B , A ] [E,B,A] [E,B,A]三点延迟之和。从DE点所求应该是 [ D , C , B , E ] [D,C,B,E] [D,C,B,E]四点之和。DE的最近公共祖先为B,可以看出对于从B点开始一直到根节点这一段我们是不需要的,也就是 w [ B ] w[B] w[B]被多加了两遍,所以我们应该减去 w [ B ] ∗ 2 w[B]*2 w[B]2。但最后答案 B B B点本身是应该计算进来的,所以我们单独加进来。其中 l c a ( D , E ) lca(D,E) lca(D,E)即为 B B B,可得式子:
f ( d , e ) = w [ D ] + W [ E ] − w [ l c a ( D , E ) ] ∗ 2 + d [ l c a ( D , E ) ] f(d,e)=w[D]+W[E]-w[lca(D,E)]*2+d[lca(D,E)] f(d,e)=w[D]+W[E]w[lca(D,E)]2+d[lca(D,E)]

我们利用这个式子在tarjan函数中就能得出每个询问的答案,当然对于起始和结束都在同一个节点的情况下,它的答案就是当前节点的出度,我们可以进行特判一下。输入输出较多,建议使用scanfprintf进行输入输出。

时间复杂度:dfs:每个点遍历一次,复杂度级别 O ( n ) O(n) O(n),tarjan算法复杂度接近 O ( n + m ) O(n+m) O(n+m)

3.Ac_code

tarjan

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=100010;

unordered_map<int,vector<int>> gra;
int n,m;
//单个点的出度
int d[N];
//记录点i到根节点的延迟
int w[N];
//并查集数组
int q[N];
//记录答案
int res[N];
int st[N];
//存下查询
vector<PII>	query[N];
//并查集查询
int find(int x){
	if(x!=q[x]) q[x]=find(q[x]);
	return q[x];
}

void dfs(int u,int fa)
{
	w[u]+=d[u];
	for(auto g:gra[u]){
		if(g==fa) continue;
		w[g]+=w[u];
		dfs(g,u);
	}
}

void tarjan(int u)
{
	st[u]=1;
	for(auto j:gra[u]){
		if(!st[j])
		{
			tarjan(j);
			q[j]=u;
		}
	}
	for(auto item: query[u]){
		int y=item.first,id=item.second;
		if(st[y]==2){
			int anc=find(y);
			res[id]=w[y]+w[u]-w[anc]*2+d[anc];
		}
	}
	st[u]=2;
}
int main() 
{
	cin>>n>>m;
	for(int i=0;i<n-1;++i){
		int a,b;
		scanf("%d%d",&a,&b);
		gra[a].push_back(b);
		gra[b].push_back(a);
		d[a]++,d[b]++;
	}
	for(int i=0;i<m;++i){
		int a,b;
		scanf("%d%d",&a,&b);
		if(a!=b){
			query[a].push_back({b,i});
			query[b].push_back({a,i});
		}else{
			res[i]=d[a];
		}
	}
	dfs(1,-1);
	for(int i=1;i<=n;++i) q[i]=i;
	tarjan(1);
	for(int i=0;i<m;++i) printf("%d\n",res[i]);
    return 0;
}

倍增LCA

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
const int N = 200010;

std::vector<int> e[N];
int n, m;
int depth[N], fa[N][30];
int root;
int w[N], d[N];
void bfs(int root)
{
	memset(depth, 0x3f, sizeof depth);
	depth[0] = 0, depth[root] = 1;
	queue<int> q;
	q.push(root);
	while (!q.empty()) {
		auto t = q.front();
		q.pop();
		for (auto j : e[t]) {
			if (depth[j] > depth[t] + 1) {
				depth[j] = depth[t] + 1;
				q.push(j);
				fa[j][0] = t;
				for (int k = 1; k <= 15; k++) {
					fa[j][k] = fa[fa[j][k - 1]][k - 1];
				}
			}
		}
	}
}

int lca(int a, int b) {
	if (depth[a] < depth[b]) swap(a, b);
	for (int k = 20; k >= 0; k--) {
		if (depth[fa[a][k]] >= depth[b]) {
			a = fa[a][k];
		}
	}
	if (a == b) return a;
	for (int k = 20; k >= 0; --k) {
		if (fa[a][k] != fa[b][k]) {
			a = fa[a][k];
			b = fa[b][k];
		}
	}
	return fa[a][0];
}
void dfs(int u, int fa)
{
	w[u] += d[u];
	for (auto g : e[u]) {
		if (g == fa) continue;
		w[g] += w[u];
		dfs(g, u);
	}
}
void solve()
{
	cin >> n >> m;
	for (int i = 0; i < n - 1; ++i) {
		int a, b;
		cin >> a >> b;
		e[a].push_back(b);
		e[b].push_back(a);
		d[a]++, d[b]++;
	}
	dfs(1, -1);
	bfs(1);
	for (int i = 0; i < m; ++i)
	{
		int a, b;
		cin >> a >> b;
		int c = lca(a, b);
		cout << w[a] + w[b] - w[c] * 2 + d[c] << '\n';
	}
}
int main()
{
	solve();
	return 0;
}

相关文章:

  • django框架技术沉淀
  • 血的教训---入侵redis并远程控制你的机器场景复现
  • 基于javaweb的养老院管理系统(java+springboot+thymeleaf+html+js+mysql)
  • 【CV】第 6 章:图像分类的实际方面
  • HazelEngine 学习记录 - Shader Asset Files
  • 网络安全—DDoS攻防
  • 【JavaWeb】之富文本编辑器
  • Synchronized底层核心原理
  • 基于JSP的房屋销售系统设计与实现
  • Arduino UNO 可视化GT-24工业级无线透传
  • 【QT 自研上位机 与 STM32F103下位机联调>>>通信测试-基础样例-联合文章】
  • c语言的三种基本结构——初学者一定要了解哦
  • 无人驾驶:高精地图与定位
  • 【论文笔记】提高超高分辨率图像的语义分割准确性的两种方法:MagNet(CVPR2021)与FCtL(ICCV2021)
  • OGG21C微服务的安装和配置
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • es的写入过程
  • Invalidate和postInvalidate的区别
  • Javascripit类型转换比较那点事儿,双等号(==)
  • Java教程_软件开发基础
  • java中的hashCode
  • js ES6 求数组的交集,并集,还有差集
  • Redis学习笔记 - pipline(流水线、管道)
  • uni-app项目数字滚动
  • Web Storage相关
  • 复习Javascript专题(四):js中的深浅拷贝
  • 给Prometheus造假数据的方法
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 开发了一款写作软件(OSX,Windows),附带Electron开发指南
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • FaaS 的简单实践
  • # include “ “ 和 # include < >两者的区别
  • ${ }的特别功能
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (待修改)PyG安装步骤
  • (独孤九剑)--文件系统
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (四)c52学习之旅-流水LED灯
  • (图)IntelliTrace Tools 跟踪云端程序
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复
  • .gitattributes 文件
  • .NET C#版本和.NET版本以及VS版本的对应关系
  • .Net接口调试与案例
  • /bin/bash^M: bad interpreter: No such file or directory
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • @31省区市高考时间表来了,祝考试成功
  • @Autowired多个相同类型bean装配问题
  • @data注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • [BeginCTF]真龙之力
  • [BUUCTF 2018]Online Tool(特详解)