【蓝桥杯每日一题】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)的思维导图或者笔记(如果有笔记的话)

相关推荐
煤泥做不到的!38 分钟前
挑战一个月基本掌握C++(第十一天)进阶文件,异常处理,动态内存
开发语言·c++
F-2H40 分钟前
C语言:指针4(常量指针和指针常量及动态内存分配)
java·linux·c语言·开发语言·前端·c++
axxy20001 小时前
leetcode之hot100---24两两交换链表中的节点(C++)
c++·leetcode·链表
chenziang11 小时前
leetcode hot100 环形链表2
算法·leetcode·链表
若亦_Royi2 小时前
C++ 的大括号的用法合集
开发语言·c++
Captain823Jack3 小时前
nlp新词发现——浅析 TF·IDF
人工智能·python·深度学习·神经网络·算法·自然语言处理
Captain823Jack3 小时前
w04_nlp大模型训练·中文分词
人工智能·python·深度学习·神经网络·算法·自然语言处理·中文分词
是小胡嘛4 小时前
数据结构之旅:红黑树如何驱动 Set 和 Map
数据结构·算法
m0_748255024 小时前
前端常用算法集合
前端·算法
呆呆的猫4 小时前
【LeetCode】227、基本计算器 II
算法·leetcode·职场和发展