【蓝桥杯每日一题】4.9网络分析(代码详解版)

终于把清明节假期时自己挖的坑给补上了

题目来源:

2069. 网络分析 - AcWing题库

参考:

Bear_king的图解
y总代码解读

思路1:

思考:

  • 题目看着,看到"发送信息后,又会发送到相邻的结点上面"这句话,觉得有点并查集的味道,但是后面又说:"计算出每个节点存储信息的大小",有些复杂!
  • 按照本人理解,并查集是类似于树状数组的集合,但是没有权值,会不会有带权并查集呢?不妨利用数组 d d d来存放并查集中的每个元素所代表的结点权值。
  • 依照题意,输入 1 1 1时,两个结点连接,也即"认大哥",输入 2 2 2时,发送消息

思路有了,先暴力试一下呗~

暴力代码:(7/10)

c++ 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m;
int num[N];
int a,x,y;
int fa[N];
int Find(int x){
    if(x!=fa[x]) fa[x]=Find(fa[x]);
     return fa[x];
}
void join(int x,int y){
    int a=Find(x);
    int b=Find(y);
    if(a!=b){
        fa[a]=b;
    }
}
int main(int argc, char** argv) {
    for(int i=0;i<100005;i++){
        fa[i]=i;
    }
    scanf("%d%d",&n,&m);
    while(m--){
        scanf("%d%d%d",&a,&x,&y);
        if(a==1){
            join(x,y);
        }else{
            int t=Find(x);
            for(int i=1;i<=n;i++){
                if(t==Find(i)){
                    num[i]+=y;  
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        printf("%d ",num[i]);
    }
        return 0;
}

思路2:

思路1无法AC,百思不得其解,看了讲解视频才了解到树形差分(其实之前学差分、二维差分的时候,我也看到过树形差分,但是没有掌握......)

思路:

  • 并查集,通过增加根节点的值,表示整棵树所有下面的结点都加上这个值
  • 对于操作1,不能直接将 a a a树连到 b b b树上,需要将a结点减去b结点的权值,才不会导致错误
  • 并查集操作时,如果需要把 b b b到根的路径压缩,数学归纳法可以证明, d [ b ] d[b] d[b]应更改为 d [ p [ b ] ] + d [ b ] d[p[b]]+d[b] d[p[b]]+d[b]
  • 很考察对并查集的理解!每次调用 f i n d ( a ) find(a) find(a)函数,会保证 a a a要么是父结点,要么它的父结点是根结点(第三层以下的结点更新后连到第二层)
  • 什么叫树上差分 ?每个结点的实际值是它走到根节点的权值之和
    但是这样操作只保证了第一第二层的结点是被维护更新好了的,如果要输出哪个点的权值,需要先对这个点 f i n d find find一下,保证更新好

AC代码:

c++ 复制代码
//树上差分+并查集  这就像一颗树
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;

int n,m;
int a,x,y;
int d[N]; //记录每个结点的权值
int fa[N];  //并查集数组


int find(int x)
//根和根的孩子是保证维护好了的,但是第三层往后的需要更新,用上面写的数学归纳法思路
//也就是如果x在第三层及以下,这里需要把它的权值处理好之后连到第二层!
{
	//路径压缩
	//如果这个结点或者它的父结点就是根节点,则不用修正操作
	if(x==fa[x]||fa[fa[x]]==fa[x]) return fa[x];
	
	int r=find(fa[x]);//先将它的父结点处理完,并合并
	d[x]+=d[fa[x]];
	fa[x]=r;//前面处理到了根节点,这里可以直接将x结点连上去了
	return r; 
}

void join(int x,int y){
	int a=find(x);
	int b=find(y);
	if(a!=b)
	{
		d[a]-=d[b]; //将a根直接连接到b根上,维护a结点的信息
		fa[a]=b;
	}
}

int main()
{
	for(int i=0;i<N;i++) fa[i]=i; //并查集初始化!
	
	scanf("%d%d",&n,&m);
	
	while(m--)
	{
		scanf("%d%d%d",&a,&x,&y);
		if(a==1){
			join(x,y);
		}
		else{
			x=find(x);
			d[x]+=y; //根节点+b
		}
	}
	
	for(int i=1;i<=n;i++)
	{
		if(i==find(i)) //本身是根节点
		{
			printf("%d",d[i]); 
		}
		//因为前面调用过了find(i),这里可以保证i是第二层的结点,即保证它的值被正确更新过
		else{
			printf("%d ",d[i]+d[find(i)]);// 权值=当前结点 + 到根结点的权值
		}
	}
	return 0;
}

结束语:

蓝桥杯更完后续会考虑每周整理计算机四大件(DS,OS,CO,CN)的思维导图或者笔记(如果有笔记的话)

相关推荐
rit84324992 分钟前
基于MATLAB的环境障碍模型构建与蚁群算法路径规划实现
开发语言·算法·matlab
hoiii1876 分钟前
MATLAB SGM(半全局匹配)算法实现
前端·算法·matlab
独自破碎E12 分钟前
大整数哈希
算法·哈希算法
纤纡.17 分钟前
逻辑回归实战进阶:交叉验证与采样技术破解数据痛点(二)
算法·机器学习·逻辑回归
czhc114007566317 分钟前
协议 25
java·开发语言·算法
春夜喜雨21 分钟前
关于内存分配的优化与设计
c++·tcmalloc·malloc·jemallc
范纹杉想快点毕业28 分钟前
状态机设计与嵌入式系统开发完整指南从面向过程到面向对象,从理论到实践的全面解析
linux·服务器·数据库·c++·算法·mongodb·mfc
fish-man32 分钟前
测试加粗效果
算法
坚定学代码41 分钟前
认识 ‘using namespace‘
c++
晓131344 分钟前
第二章 【C语言篇:入门】 C 语言基础入门
c语言·算法