并查集题目

news2024/11/20 4:18:28

并查集是一种十分常用并且好用的数据结构

并查集可以动态维护若干个不重叠的集合,支持合并与查询操作,是一种树形的数据结构


并查集的基础应用

村村通

对于这道题我们只需要求连通块的数量,然后将这几个联通快看成点,我们可以知道联通的n个点中最少有n-1边

#include <iostream>
#include <cstring>

using namespace std;
const int N = 1010;
int p[N], st[N];

int find(int x)
{
    if(x == p[x])   return x;
    return p[x] = find(p[x]);
}

int main()
{
    // freopen("1.in", "r", stdin);
    while(1)
    {
        memset(st, 0, sizeof st);
        int n, ans = 0;
        scanf("%d", &n);
        if(n == 0)  return 0;
        else
        {
            int m;  scanf("%d", &m);
            for(int i = 1; i <= n; ++ i)    p[i] = i;
            for(int i = 0; i < m; ++ i)
            {
                int x, y;   scanf("%d%d", &x, &y);
                int a = find(x);
                int b = find(y);
                if(a != b)  p[a] = b;
            }
            for(int i = 1; i <= n; ++ i)
            {
                int x = find(i);
                if(!st[x])  ans ++, st[x] = 1;;
            }
            cout << ans - 1 << endl;
        }
    }
}

带权并查集

推导部分和

这道题的是带边权并查集的应用,比较难想到的是建图

对于每个区间l, r,k, 我们可以由前缀和s[r] - s[l - 1] = k,我们从r连一条l-1的边

WechatIMG819.png

#include <iostream>

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
//p[N]数组用来做并查集
int p[N], n, m, q;
//s[N]数组是当前点到根结点的权值和,也是前缀和
LL s[N];

//并查集的查询操作(带路径压缩)
int find(int x)
{
    if(x == p[x])   return x;
    else
    {
        int t = find(p[x]);
        s[x] += s[p[x]];
        p[x] = t;
        return t;
    }
}


int main()
{
    // freopen("1.in", "r", stdin);
    cin >> n >> m >> q;
    for(int i = 1; i <= n; ++ i)    p[i] = i;
    for(int i = 0; i < m; ++ i)
    {
        int l ,r;
        LL k; 
        cin >> l >> r >> k;
        int t1 = find(l - 1), t2 = find(r);
        if(t1 != t2)
        {
            p[t2] = t1;
            s[t2] = s[l - 1] - s[r] + k;
        }
    }
    while(q --)
    {
        int l, r;cin >> l >> r;
        int t1 = find(l - 1), t2 = find(r);
        if(t1 != t2)    puts("UNKNOWN");
        else printf("%lld\n", s[r] - s[l - 1]);
        
    }
    return 0;
}

并查集的拓展域


例题团伙

#include <iostream>
using namespace std;
const int N = 2010;
int p[N];
bool st[N];
int find(int x)
{
    if(p[x] == x)   return p[x];
    return p[x] = find(p[x]);
}
void merge(int x, int y)
{
    int px = find(x), py = find(y);
    if(px != py)    p[px] = py;
}

int main()
{
    // freopen("1.in", "r", stdin);
    int n, m;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= 2 * n; ++ i)    p[i] = i;
    for(int i = 0; i < m; ++ i)
    {
        char op; int x, y;
        cin >> op >> x >> y;
        if(op == 'F')
        {
            merge(x, y);
            // merge(x + n, y + n);
        }
        else
        {
            merge(x + n, y);
            merge(x, y + n);
        }
    }
    // for(int i = 1; i <= n; ++ i)    cout << i << ' ' << find(i) << endl;    
    int cnt = 0;
    for(int i = 1; i <= n; ++ i)
        if(!st[find(i)])
        {
            cnt ++;
            st[find(i)] = 1;
        }
    cout << cnt << endl;
    return 0;
}

这是一道并查集的拓展域的题目也可以用带权并查集去做

本题和普通的并查集不同,普通并查集维护的是不相交集合,是一种传递性的关系如亲戚的亲戚是亲戚

本题是天敌的天敌是食物,是一种环形的关系

我们如果用拓展域来解决这道题目的话可以用3个并查集来维护3种关系,第一种是同类关系,第二种是食物关系,第三种是天敌

就本题而言我们不用真开三个并查集,我们可以将三个并查集开到一个数组里,下标的范围代表不同的集合

WechatIMG824.jpeg

#include <iostream>

using namespace std;
const int N = 5e4 + 10;
int p[N * 3], ans, k, n;

//1--n代表x的同类,n + 1 -- 2n代表x的食物, 2n + 1 -- 3n代表x的天敌
int find(int x)
{
    if(x == p[x])   return x;
    return p[x] = find(p[x]);
}
void merge(int x, int y)
{
    int px = find(x), py = find(y);
    p[py] = px;
}
int main()
{
    cin >> n >> k;
    for(int i = 1; i <= 3 * n; ++ i)    p[i] = i;
    for(int i = 0; i < k; ++ i)
    {
        int d, x, y;scanf("%d%d%d", &d, &x, &y);
        if(x > n || y > n)  ans ++;
        //x、y是同类
        else if(d == 1)
        {
            //如果根据前面的信息,我们可以知道y在x的食物域,
            //或者y在x的天敌域中,说明这句话是假话
            if(find(x + n) == find(y) || find(x + n + n) == find(y))    ans ++;
            //如果根据前面的信息,不能判断这句话是错误的,那么就讲这句话
            //当成对的并且更新x的三个域
            else
            {
                //y在x的同类域中
                merge(x, y);
                //y的食物和x的食物是同类
                merge(x + n, y + n);
                //y的天敌和x的天敌是同类
                merge(x + n + n, y + n + n);
            }
        }
        //如果x吃y
        else
        {
            //若果y在x的同类域或者,y在x的天敌域说明这句话是假话
            if(find(x) == find(y) || find(x + n + n) == find(y))    ans ++;
            //这句话是真话就更新x的三个域
            else
            {
                //y在x的食物域中
                merge(x + n, y);
                //y的食物是x的天敌
                merge(x + n + n, y + n);
                //y的天敌是x的同类
                merge(x, y + n + n);
            }
        }
    }
    cout << ans << endl;
    return 0;
}

牛客修棋盘

我们通过观察可以知道,走到每个点的奇偶性是确定的

同时我们的合法状态只有两种


如果我们对每个点都修改的话,我们能达到的状态如下:

所以我们每次修改次数最少的话应该是考虑我们每个点都修改的状态,当我们把每个点都修改的话就是互补的一个状态

#include <iostream>
#include <queue>

#define x first
#define y second
using namespace std;
typedef pair<int, int>PII;
const int N = 1010;
int res, n, m;
char g[N][N];
bool st[N][N];


int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; ++ i)
        for(int j = 1; j <= m; ++ j)
        {
            char ch; cin >> ch;
            int x = ch -'0';
            if((i + j) % 2 == 0 && x == 1)    res ++;
            if((i + j) % 2 && x == 0)    res ++;
        }
    if(res == m * n)    puts("0");
    else    cout << res << endl;
    return 0;
}

P5937 [CEOI1999] Parity Game

题目的具体思路如下:考虑一段连续区间的1个数的奇偶,可以转化为考虑考虑两个端点前缀和的奇偶性上,分为两种情况,如果[l, r]区间内1的个数为偶数,说明sum[r]和sum[l - 1]包含1的个数的奇偶性相同,反之若为奇数则两个包含1的个数的奇偶性相反,我们知道奇偶性具有传递性,这样我们就可以种类并查集来维护,注意n的范围比较大,但是实际的需要用到的点的个数是比较小的,这里我们需要离散化一下。

#include <bits/stdc++.h> 
#define LL long long 
using namespace std;

const int N = 1e4 + 10;
int p[N * 2 + 10], n, m, k;
map<int, int>mp;
int b[N * 2];

struct wy
{
	int l, r, op;	
}q[N];

int find(int x)
{
	if(x != p[x])	p[x] = find(p[x]);
	return p[x];
}

void merge(int x, int y)
{
	int px = find(x), py = find(y);
	p[py] = px;
}

int query(int x)
{
	return lower_bound(b + 1, b + 1 + k, x) - b;
}
void solve()
{
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= m; ++ i)
	{
		int l, r, op;
		char s[5];
		scanf("%d%d%s", &l, &r, s);
		if(s[0] == 'e')	op = 1;
		else op	= 2;
		q[i] = {--l, r, op};
		b[++ k] = l;
		b[++ k] = r;
	} 
	sort(b + 1, b + 1 + k);
	k = unique(b + 1, b + 1 + k) - (b + 1);

	for(int i = 1; i <= 2 * k; ++ i) p[i] = i;
	for(int i = 1; i <= m; ++ i)
	{
		int l = query(q[i].l), r =  query(q[i].r), op = q[i].op;
		if(op == 1) 
		{
			
			if(find(l) == find(r + k) || find(r) == find(l + k))
			{
				printf("%d", i - 1);
				return;
			}
			else
			{
				merge(l, r);
				merge(l + k, r + k);
			}
		
		}
		else
		{
			if(find(l) == find(r) || find(r + k) == find(l + k))
			{
				printf("%d", i - 1);
				return;
			}
			else
			{
				merge(l, r + k);
				merge(r, l + k); 	
			}
		}	
	}
	printf("%d", m);
}
int main()
{
//	freopen("1.in", "r", stdin);
	solve(); 
	return 0;
}

P1955 [NOI2015] 程序自动分析

这道题目是相等关系,相等关系也具有传递性,明显我们可以用并查集来维护。
我们可以先对处理相等,然后去查询不相等的是否在一个集合里面如果在一个集合里面则说明这样的点是不存在的。这道题目的数据的范围很大,但实际用到的很少,我们需要对数据进行离散化。

#include <bits/stdc++.h> 
#define LL long long 
using namespace std;

const int N = 1e6 + 10;
int n, m, p[N], a[N], k, tot;
struct wy{
	int x, y, e;
}q[N];

int find(int x)
{
	if(x != p[x])	p[x] = find(p[x]);
	return p[x];
} 

void merge(int x, int y)
{
	int px = find(x), py = find(y);
	p[py] = px;
}

void solve()
{
	scanf("%d", &n);
	for(int i = 1; i <= n; ++ i){
		int x, y, e;
		scanf("%d%d%d", &x, &y, &e);
		a[++ tot] = q[i].x = x;
		a[++ tot] = q[i].y = y;
		q[i].e = e;	
	}
	sort(a + 1, a + 1 + tot);
	tot = unique(a + 1, a + 1 + tot) - a - 1;
	for(int i = 1; i <= tot; ++ i)	p[i] = i;
	for(int i = 1; i <= n; ++ i)
	{
		q[i].x = lower_bound(a + 1, a + tot + 1, q[i].x) - a - 1;
		q[i].y = lower_bound(a + 1, a + tot + 1, q[i].y) - a - 1;
		if(q[i].e == 1){
			merge(q[i].x, q[i].y);
		}
	}

	for(int i = 1; i <= n; ++ i){
		int x = q[i].x;
		int y = q[i].y;
		if(q[i].e == 0 && find(x) == find(y)){
			puts("NO");
			return;
		}
	}
		puts("YES");
}

int main()
{
// 	freopen("1.in", "r", stdin);
	scanf("%d", &k);
	while(k--) solve(); 
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1031902.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【算法练习Day3】 移除链表元素设计链表反转链表

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 移除链表元素其他问题 设…

【LeetCode热题100】--53.最大子数组和

53.最大子数组和 使用动态规划&#xff1a; 状态定义&#xff1a;设动态规划列表dp&#xff0c;dp[i]代表以元素nums[i]为结尾的连续子数组最大和 转移方程&#xff1a;若dp[i-1]≤0,说明dp[i-1]对dp[i]产生负贡献&#xff0c;即dp[i-1]nums[i]还不如nums[i]本身大 初始状态&…

基于Python+Pygame实现一个俄罗斯方块小游戏【完整代码】

俄罗斯方块&#xff0c;一款起源于上世纪80年代的经典电子游戏&#xff0c;凭借简单的规则和独特的魅力&#xff0c;一跃成为全球家喻户晓的经典。你知道其实只需要一些基础的编程知识&#xff0c;就可以自己实现它吗&#xff1f;今天&#xff0c;我们将使用Python的Pygame库&a…

2023年前端流行什么技术和框架了?

Web前端三大主流框架有React、Vue.js和Angular&#xff0c;由于接触过Vue.js&#xff0c;接下来主讲最新的Vue3.0&#xff01; Vue3.0作为最新版本的Vue.js框架&#xff0c;拥有更强大的性能和更丰富的功能&#xff0c;为低代码开发平台注入了全新的活力。而JNPF快速开发平台作…

Anchor DETR

Anchor DETR(AAAI 2022) 改进&#xff1a; 提出了基于anchor的对象查询提出Attention变体-RCDA 在以前DETR中&#xff0c;目标的查询是一组可学习的embedding。然而&#xff0c;每个可学习的embedding都没有明确的意义 &#xff08;因为是随机初始化的&#xff09;&#xff…

2024年天津专升本文化课考试大纲发生了哪些变化

2024年天津专升本文化课考试语文、数学、计算机、英语最新大纲发生了哪些变化 高职升本科《计算机应用基础》大纲更改详解:新增计算机发展新技术、win7变更为 win10、word2010变为word2019、 新 增其他常用功能模块、Excel2010变 更为Excel2019、新增演示文稿制作软件PowerPoi…

iPhone15线下购买,苹果零售店前门店排长队

今年的苹果新品发布会于北京时间 9 月 13 日凌晨举行&#xff0c;并于 9 月 15 日&#xff08;周五&#xff09;开启订购&#xff0c;9 月 22 日&#xff08;周五&#xff09;起正式发售。 据多位网友反馈&#xff0c;首批苹果 iPhone15 系列手机、Apple Watch Ultra 2 / Seri…

VBA技术资料MF59:从二维变体数组中删除一行数据

【分享成果&#xff0c;随喜正能量】小小的善业&#xff0c;能赢来大的利益&#xff0c;小小的恶业&#xff0c;同样也能招致严重的后果。这正如古语所云&#xff1a;“莫以善小而不为&#xff0c;莫以恶小而为之。。 我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效…

【数据库】Sql Server 2022通过临时表和游标遍历方式逻辑处理获取目标数据

2023年&#xff0c;第39周。给自己一个目标&#xff0c;然后坚持总会有收货&#xff0c;不信你试试&#xff01; 今天有个小伙伴咨询一个Sql Server处理数据的问题&#xff0c;刚好重温下SqlServer临时表和游标的知识点 目录 一、需求点描述二、临时表2.1、局部临时表&#xff…

计算机网络相关知识点

谈一谈对OSI七层模型和TCP/IP四层模型的理解&#xff1f; 这两种模型都是网络通信中重要的参考模型,他们的设计和功能有一些区别。 首先OSI&#xff0c;OSI七层模型&#xff0c;也被称为开放系统互联参考模型&#xff0c;是一种在国际标准化组织&#xff08;ISO&#xff09;中…

网络知识——局域网和交换机

定义&#xff1a; 局域网&#xff08;Local Area Network&#xff0c;简称LAN&#xff09;是指在某一区域内由多台计算机互联成的计算机组。广域网&#xff08;Wide Area Network&#xff0c;简称WAN&#xff09;是指跨越单个建筑物或大型园区&#xff0c;连接分布在特定地理区…

2023 Sui Builder House全球之旅圆满收官

2023年的最后一场Builder House于上周在新加坡举行&#xff0c;包括主题演讲、小组讨论和研讨会等聚焦Sui的现在和未来的活动。其中&#xff0c;zkLogin是本次活动的最大亮点。作为一种新的Sui原语&#xff0c;zkLogin允许用户使用Web2身份验证创建帐户&#xff0c;有望推动大规…

计算机网络常见问题

1.谈一谈对OSI七层模型和TCP/IP四层模型的理解&#xff1f; 1.1.为什么要分层&#xff1f; 在计算机中网络是个复杂的系统&#xff0c;不同的网络与网络之间由于协议&#xff0c;设备&#xff0c;软件等各种原因在协调和通讯时容易产生各种各样的问题。例如&#xff1a;各物流…

通过 BigQuery 中的 11 个新链增强 Google Cloud 的区块链数据服务

2018 年初&#xff0c;Google Cloud 与社区合作&#xff0c;通过BigQuery 公共数据集实现区块链数据民主化&#xff1b;2019 年&#xff0c;又扩展了六个数据集&#xff1b;今天&#xff0c;我们在 BigQuery 公共数据集中添加了 11 个最受欢迎的区块链预览版。我们也在对该程序…

windbg -I之后如何恢复原有的

直接运行了一下windbg -I&#xff0c;抓取了注册表行为&#xff0c;然后这里记录一下&#xff0c;方便翻阅。 抓取到的windbg的注册表 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug\Debugger 将值改为 "C:\WINDOWS\system32\vsji…

Linux:进程概念的引入和理解

文章目录 进程的初步理解进程的实质理解查看进程 前面对操作系统有了一个基础的认知&#xff0c;从中得出的最重要的一个思想是&#xff0c;在认识一个新事物前要先描述&#xff0c;再组织&#xff0c;有了这样的思想也可以用于学习进程的概念 进程的初步理解 有了前面的思想…

三维模型3DTile格式轻量化在三维展示效果上的重要性分析

三维模型3DTile格式轻量化在三维展示效果上的重要性分析 三维模型3DTile格式轻量化在三维展示效果上扮演着至关重要的角色。随着计算机图形学和虚拟现实技术的不断发展&#xff0c;我们已经可以创建和渲染非常精细和复杂的三维模型&#xff0c;以实现逼真的视觉效果。然而&…

3D大模型如何轻量化?试试HOOPS Communicator,轻松读取10G超大模型!

随着计算机技术的不断发展&#xff0c;3D模型在各行各业中的应用越来越广泛。然而&#xff0c;随着模型的复杂性和规模不断增加&#xff0c;处理和浏览超大型3D模型变得越来越具有挑战性。本文将探讨如何轻量化3D大模型&#xff0c;以及如何使用HOOPS Communicator来读取和浏览…

IC芯片测试:如何对芯片静态功耗进行测试?

静态功耗也叫静态电流&#xff0c;是指芯片在静止状态下的电流或者是指芯片在不受外界因素影响下自身所消耗的电流。静态功耗对于芯片来说是衡量一款芯片的功耗与效率非常重要的指标。 传统手动测试静态功耗只需在芯片的输入端串上一台万用表&#xff0c;然后对芯片各个端口添加…

C语言 指针 模拟排序函数 指针数组笔试题上

目标&#xff1a;使用【冒泡排序】的算法&#xff0c;模拟一个排序函数&#xff0c;可以排序任意类型的数据 void print_arr(int arr[], int sz)//打印函数 只能接受整型数组 {int i 0;for (i 0; i < sz; i){printf("%d ", arr[i]);}printf("\n"); }…