13 树的应用-并查集

昨晚熬夜写出来了 电脑没电了没保存, 描述又要重新打过。。。。

心好累啊



1、并查集基本描述:是一种简单的集合表示
有三种基本操作:
①Union:把S中子集合Root2并入子集合Root1中。
②Find:查找子集合S中单元素所在的子集合,返回子集合的名字
③initial:把集合中每一个元素都初始化为只有一个单元素的子集合

写的时候添加了路径压缩功能:

实际上是把子元素存储的内容直接改向根结点,在访问的时候可以大大提升速度。查阅了一下 这个功能比较多地是与查找函数合并了。在每查找一个结点以后直接按照子元素到根元素的路径修改路径上每一个元素存放的内容,使其直接指向根结点,这样以后访问的时候可以提高效率。
2、并查集的特点:
用树的双亲表示作为存储结构,每个自己和以一棵树来表示。
所有表示子集合的树构成表示全集合的森林,存放在双亲表示数组之中。
3、适用场合:
查阅了一些资料,并查集实际上非常适合用于解决一些判断动态连通性的题目(不许给出具体路径),通过输入点的前后继关系建立集合,通过判断两个点是否同属于同一个组来判断是否属于同一个集合。

4、代码实现

 1 #include<stdio.h>
 2 #include<iostream>
 3 using namespace std;
 4 #define SIZE 10
 5 int UFset[SIZE];
 6 /*初始化:初始化所有元素集合为0*/
 7 void initial(int s[])
 8 {
 9     int i;
10     for(i=0; i<SIZE; i++)
11     {
12         s[i]=-1;
13     }
14     printf("init successful.\n");
15 }
16 /*查找:在并查集中查找并返回包含元素x的树的根*/
17 int Find(int S[],int x)
18 {
19     while(S[x]>=0)
20         x=S[x];
21     return x;
22 }
23 /*合并:求两个不相交子集合的并集*/
24 void Union(int S[],int Root1,int Root2)
25 {
26     S[Root2]=Root1;
27 }
28 void showUFSets(int s[])
29 {
30     int i;
31     printf("|");
32     for(i=0; i<SIZE; i++)
33     {
34         printf("%d:%d|",i,s[i]);
35     }
36     printf("\n");
37 }
38 /*路径压缩:更新整个集合的元素
39 使其在访问的过程中可以直接找到它的根结点……
40 看到网上有说这个东西就强行写一个加上去先,具体做题的时候可以把这个算法整合到find函数中,一边找一边更新……
41 */
42 void ysroad(int s[])
43 {
44     int father;
45     for(int i=0;i<SIZE;i++)
46     {
47         if(s[i]!=-1){
48         father=Find(s,i);//找到i元素的根结点
49         s[i]=father;
50         }
51     }
52 }
53 int main()
54 {
55     int r1[SIZE],r2[SIZE];
56     initial(r1);
57
58     showUFSets(r1);
59     initial(r2);
60     showUFSets(r2);
61     printf("Test of Union");
62     int father,son;
63     cin>>father;
64     cin>>son;
65     while(son!=0)
66     {
67         r1[son]=father;
68         cout<<"successful"<<endl;
69         cin>>father;
70         cin>>son;
71     }
72     cout<<"before:"<<endl;
73     showUFSets(r1);
74     ysroad(r1);
75 cout<<"after"<<endl;
76     showUFSets(r1);
77     return 0;
78 }

5、代码实现截图

时间: 2024-10-13 01:42:17

13 树的应用-并查集的相关文章

2017端午欢乐赛——Day1T3(树的直径+并查集)

//前些天的和jdfz的神犇们联考的模拟赛.那天上午大概是没睡醒吧,考场上忘了写输出-1的情况,白丢了25分真是**. 题目描述     小C所在的城市有 n 个供电站,m条电线.相连的供电站会形成一个供电群,那么为了节省材料,供电群是一棵树的形式,也即城市是一个森林的形式(树:V个点,V-1条边的无向连通图,森林:若干棵树).每个供电群中不需要所有供电站都工作,最少只需要一个工作,其余的就都会通过电线收到电,从而完成自己的供电任务.当然,这样会产生延迟.定义两个供电站的延迟为它们之间的电线数量

Wikioi 2492 树状数组+并查集(单点更新区间查询)

刚开始做的时候用线段树做的,然后就跳进坑里了--因为要开方,所以区间的值都得全部变,然后想用lazy标记的,但是发现用不了,单点更新这个用不了,然后就不用了,就T了.然后实在不行了,看了别人的题解,原来是用树状数组+并查集的方法,唉--没想到啊! 因为开方之后多次那个数就会变成1了,所以是1的时候开方下去就没用了.树状数组更新的时候就把其更新的差更新即可,太机智了这题-- 昨天做了,然后出错找了好久都找不出来,原来是把s[i]写成c[i]了,然后答案一直错,晕-- #include <iostr

hdu 5458 Stability(树链剖分+并查集)

Stability Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)Total Submission(s): 1347    Accepted Submission(s): 319 Problem Description Given an undirected connected graph G with n nodes and m edges, with possibly r

BZOJ 3211 花神游历各国 (树状数组+并查集)

题解:首先,单点修改求区间和可以用树状数组实现,因为开平方很耗时间,所以在这个方面可以优化,我们知道,开平方开几次之后数字就会等于1 ,所以,用数组记录下一个应该开的数,每次直接跳到下一个不是1的数字进行开平方,至于这个数组,可以用并查集维护. #include <cstdio> #include <cmath> #include <iostream> using namespace std; typedef long long LL; LL c[100005]; in

HDU 5458 Stability (树链剖分+并查集+set)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5458 给你n个点,m条边,q个操作,操作1是删边,操作2是问u到v之间的割边有多少条. 这题要倒着做才容易,倒着加边. 因为这题最后保证所有的点一定连通,所以可以构建一棵树,树链剖分一下.要是u到v之间只有一条边,那便是一条割边.而加边的话,就是将u到v之间的边权都+1,边权等于1的话是桥,大于1的话就不是了.所以我们初始化树的时候,可以将边权初始化为1,加边操作将边权赋值为0.求u到v的割边个数的

[BZOJ3211]花神游历各国&amp;&amp;[BZOJ3038] 上帝造题的七分钟2 树状数组+并查集

3211: 花神游历各国 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 4057  Solved: 1480[Submit][Status][Discuss] Description Input Output 每次x=1时,每行一个整数,表示这次旅行的开心度 Sample Input 4 1 100 5 5 5 1 1 2 2 1 2 1 1 2 2 2 3 1 1 4 Sample Output 101 11 11 HINT 对于100%的数据,

bzoj3694: 最短路(树链剖分/并查集)

bzoj1576的帮我们跑好最短路版本23333(双倍经验!嘿嘿嘿 这题可以用树链剖分或并查集写.树链剖分非常显然,并查集的写法比较妙,涨了个姿势,原来并查集的路径压缩还能这么用... 首先对于不在最短路径树上的边x->y,设t为最短路径树上lca(x,y),则t到y上的路径上的点i到根的距离都可以用h[x]+dis[x][y]+h[y]-h[i](h[]为深度)来更新,因为h[i]一定,只要让h[x]+dis[x][y]+h[y]最小就行,这里用树剖直接修改整条链上的数,就可以过了. 并查集的

codeforces 455C C. Civilization(树形dp+树的直径+并查集)

题目链接: codeforces 455C 题目大意: 给出一些点,他们之间初始存在一些边,给出两种操作,第一种是查询某个点所在的树的直径,另一种是将两个树合并,要求使合并后的树的直径最小. 题目分析: 首先算取没做操作前的连通块里的树的直径,也就是先dfs一遍,找到深度最大的点,然后从这个点再搜,找到的最远的距离就是这棵树的直径,因为可以证明从根搜深度最大的点一定是树的直径的一个端点,因为它可以通过到达次大的深度的点或者找到与它公共祖先不在根处的获得树的直径. 然后每次合并,我们可以知道得到的

【bzoj4551】[Tjoi2016&amp;Heoi2016]树 离线处理+并查集

题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个结点,可以打多次标记.)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖先)你能帮帮他吗? 输入 输入第一行两个正整数N和Q分别表示节点个数和操作次数接下来N-1行,每行两个正整数u,v(1≤u,v≤n)表示u到v有一条有向边接下来Q行,形如"oper