[hiho 14]并查集

题目描述

并查集,顾名思义有两个操作:合并和查询。

并就是把两个集合合并到一起。

查就是查询两个节点是否属于同一个集合。

每个节点有一个父节点。一个集合内存在一个唯一的根,判断根的条件就是节点的父节点是不是该节点本身。

合并操作就是把一个集合的根接到另一个集合的根上。

而查询操作就是找两个对象是否有同一个根。

查询过程中可以顺便进行路径压缩以优化后续查询:即让查找路径上所有节点的父节点直接等于根节点。

#include <iostream>
#include <algorithm>
#include <cstring>

#define MAX 200005

using namespace std;

int root[MAX];
char names[MAX][50];

unsigned int BKDRHash(char *str)
{
    unsigned int seed = 131;
    unsigned int hash = 0;

    while (*str)
    {
        hash = hash * seed + (*str++);
    }

    return (hash & 0x7FFFFFFF) % MAX;
}

int get_index(char *str) {
	int res = BKDRHash(str);
	while (strlen(names[res]) != 0 && strcmp(str, names[res])) {
		res++;
		res %= MAX;
	}
	if (strlen(names[res]) == 0) {
		strcpy(names[res], str);
	}
	return res;
}

int get_root(int a) {
	if (root[a] == -1) root[a] = a;
	if (a != root[a]) {
		root[a] = get_root(root[a]);
	}
	return root[a];
}

int main() {
	int n;
	int op;
	char s1[50], s2[50];
	int a, b;
	memset(root, -1, sizeof(root));
	cin >> n;
	while (n--) {
		cin >> op >> s1 >> s2;
		a = get_index(s1);
		b = get_index(s2);
		if (op == 0) {
			int fa = get_root(a), fb = get_root(b);
			root[fa] = fb;
		} else {
			int fa = get_root(a), fb = get_root(b);
			if (fa == fb) {
				cout << "yes" << endl;
			}
			else {
				cout << "no" << endl;
			}
		}
	}
	return 0;
}
时间: 2024-12-14 12:46:47

[hiho 14]并查集的相关文章

14 并查集

基本概念 并查集是一种树型的数据结构,用于处理一些不交集的合并及查询问题 示意图 常用方法 Find:确定元素属于哪一个子集.可以用来确定两个元素是否属于同一子集 Union: 将两个子集合并成同一个集合 示意图 代码实现(伪代码) function MakeSet(x) x.parent := x function Find(x) if x.parent == x return x else return Find(x.parent) function Union(x, y) xRoot :=

【hiho】14 无间道之并查集【图论--并查集】

传送门:无间道之并查集 分析 并查集的分析可以看上面的传送门,写的挺好的了. 其实在我看来并查集就是一种方便的维护集合的一种技巧,提出了代表元素这一概念. My AC Code #include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1e5+5; int represent[maxn]; int find_represent(int x) {

Educational Codeforces Round 14 D. Swaps in Permutation (并查集orDFS)

题目链接:http://codeforces.com/problemset/problem/691/D 给你n个数,各不相同,范围是1到n.然后是m行数a和b,表示下标为a的数和下标为b的数可以交换无数次.问你最后字典序最大的数列是什么. 将下面的a和b用并查集联系起来存到祖节点对应的数组中,然后从大到小排序数组,最后依次按照父节点的数组中的顺序输出. 也可以用dfs的方法解(略麻烦),形成一个环路的就在一个数组中... 1 //并查集 2 #include <bits/stdc++.h> 3

【二分图】【并查集】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem L. Canonical duel

给你一个网格(n<=2000,m<=2000),有一些炸弹,你可以选择一个空的位置,再放一个炸弹并将其引爆,一个炸弹爆炸后,其所在行和列的所有炸弹都会爆炸,连锁反应. 问你所能引爆的最多炸弹数. 转化成: 将行列当成点,炸弹当成边,然后你可以给这个二分图加1条边,问你最大的连通块的边的数量. 可以通过枚举所有可以建的边,通过并查集来尝试更新答案.由于一条边必然会让总度数+2,所以一个连通块的边数是所有点的度数之和/2. 并查集不必要动态维护集合的大小,一开始就建好并查集,提前统计好即可. 最后

【hihoCoder第十四周】无间道之并查集

就是基础的并查集.0代表合并操作,1代表查询操作.一开始以为会卡路径压缩,忐忑的交了一版裸并查集,结果AC了.数据还是很水的. 以后坚持做hiho,当额外的练习啦~ 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 map<string, int> Hash; 5 int Father[1000005]; 6 7 int getFather (int x) { 8 if (x != Father[x]) { 9 return

CodeForces 745C Hongcow Builds A Nation 并查集

题意: 给了你n个城市 m条边 k个政府 每个政府管辖的区域内不能和其他政府的区域有相连 即政府之间不存在路径 问你在维护这种关系的同时 最多再加多少条边 思路: 先找出来每个联通块 再找出来没有归属的孤立的点 把他们都放到最大的联通块里 然后每个联通块之间的点两两连边是n*(n-1)/2条边 最后算出来的ans-m就好了 (看别人的博客学了一个max_element 1 #include<bits/stdc++.h> 2 #define cl(a,b) memset(a,b,sizeof(a

并查集(个人模版)

并查集: 1 int find(int a) 2 { 3 int r=a; 4 while(f[r]!=r) 5 r=f[r]; 6 int i=a; 7 int j; 8 while(i!=r) 9 { 10 j=f[i]; 11 f[i]=r; 12 i=j; 13 } 14 return r; 15 } 16 int merge(int a,int b) 17 { 18 int A,B; 19 A=find(a); 20 B=find(b); 21 if(A!=B) 22 { 23 f[B

并查集应用

题目描述: One way that the police finds the head of a gang is to check people's phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls

HDU 5441 离线处理 + 并查集

题意:给n个节点m条带权值边的无向图.然后q个问题,每次询问点对的数目,点对需要满足的条件是:1)连通:2)其路径的最大权值不能超过询问值. 分析:如果没次询问一次,dfs一次,很可能超时,因此可以用并查集.离线处理,把边按权值排序,把问题按大小排序.然后离线的过程就是不断向图中加边的过程. 比如样例如下: 然后离线处理,排完序后将会是一条一条的加边:问题也排了序,因此是个累加过程... 1 #include <cstdio> 2 #include <iostream> 3 #in