《算法竞赛进阶指南》0x41 并查集

news/2024/9/22 16:51:48/

0x41 并查集

程序自动分析

题意:

一些变量,之间是相等与不相等关系。询问所有约束条件是否可以同时满足

解析:

并查集。并查集维护相等的变量,对于不相等变量,检查是否在在同一并查集里。注意离散化

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
const int maxn = 1e6+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;int n;
int fa[maxn];
struct query{int a, b, op, id;bool operator < (const query &b) const{return op > b.op;}
}q[maxn];
vector<int> t;
void init(int MAX){for(int i = 1; i <= MAX; i++)fa[i] = i;
}
int find(int x){return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);
}
void merge(int x, int y){int fx = find(x);int fy = find(y);if(fx != fy){fa[fx] = fy;}
}
void solve(){cin >> n;t.clear();for(int i = 1; i <= n; i++){cin >> q[i].a >> q[i].b >> q[i].op;q[i].id = i;t.push_back(q[i].a);t.push_back(q[i].b);}sort(t.begin(), t.end());t.erase(unique(t.begin(), t.end()), t.end());for(int i = 1; i <= n; i++){q[i].a = lower_bound(t.begin(), t.end(), q[i].a) - t.begin()+1;q[i].b = lower_bound(t.begin(), t.end(), q[i].b) - t.begin()+1;}init(n << 1);sort(q+1, q+1+n);for(int i = 1; i <= n; i++){if(q[i].op == 1){merge(q[i].a, q[i].b);}else if(q[i].op == 0){int fx = find(q[i].a);int fy = find(q[i].b);if(fx == fy){cout << "NO" << endl;return;}}}cout << "YES" << endl;return;
}
int main(){ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);int T;cin >> T;while(T--)solve();return 0;
}


银河英雄传说

题意:

一些船,一开始每艘船单独一列。

两种操作:

  • 将某一船所在列接到另一列的尾部
  • 询问两艘船在同一列中之间有多少艘船

解析:

带权并查集。dis[x]dis[x]dis[x]xxxfa[x]fa[x]fa[x] 之间的边权。

对于 findfindfind 函数,将 dis[x]dis[x]dis[x] 修改为到根节点路径上的边权和

对于 mergemergemerge 函数,如果将 xxx列 接到 yyy 列后,dis[x]=size[y]dis[x] = size[y]dis[x]=size[y],所以需要维护每个并查集的大小

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
const int maxn = 3e4+10;
const int INF = 0x3f3f3f3f;
const int MAX = 3e4;
typedef pair<int, int> pii;int fa[maxn], dis[maxn], siz[maxn];
int find(int x){if(x != fa[x]){int t = fa[x];fa[x] = find(fa[x]);dis[x] += dis[t];siz[x] = siz[fa[x]];}return fa[x];
}
void merge(int x, int y){int fx = find(x);int fy = find(y);if(fx != fy){dis[fx] = dis[fy] + siz[fy];siz[fy] += siz[fx];siz[fx] = siz[fy];fa[fx] = fy;}
}
int main(){ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);int T, x, y;char op;cin >> T;for(int i = 1; i <= MAX; i++)fa[i] = i, siz[i] = 1;while(T--){cin >> op >> x >> y;if(op == 'M')merge(x, y);else if(op == 'C'){int fx = find(x);int fy = find(y);if(fx != fy)cout << -1 << endl;else if(x != y)cout << abs(dis[x]-dis[y])-1 << endl;elsecout << 0 << endl;}}return 0;
}


奇偶游戏

题意:

给定01序列 sss。依次给定序列满足的条件 (l,r,t)(l,r,t)(l,r,t) 表示 s[l...r]s[l...r]s[l...r] 中 1 的个数是奇数还是偶数。
询问最后一个不产生矛盾的条件。

解析:

带权并查集。

已知 s[l...r]s[l...r]s[l...r] 中1的个数的奇偶性,前缀和的思想,可以得到 s[1...l−1]s[1...l-1]s[1...l1]s[1...r]s[1...r]s[1...r] 的1的个数奇偶性是否相同。

权值 val[x]val[x]val[x] 表示 xxxfa[x]fa[x]fa[x] 奇偶性是否相同,0为相同,1为不同。

路径压缩的时候,val[x]val[x]val[x] 的值为路径上权值的异或。

两个集合合并的时候,自己和自己的奇偶性一定相同,所以 val[fa[x]]=val[x]⊕val[y]⊕wval[fa[x]] = val[x]\oplus val[y]\oplus wval[fa[x]]=val[x]val[y]wwwwx,yx,yx,y 的奇偶性是否相同。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;int fa[maxn], val[maxn];
struct node{int l, r, t;
}q[maxn];
vector<int> t;
int n, m;
string s;int find(int x){if(x != fa[x]){int rt = find(fa[x]);val[x] ^= val[fa[x]];fa[x] = rt;}return fa[x];
}
void merge(int x, int y, int w){int fx = find(x);int fy = find(y);if(fx != fy){fa[fx] = fy;val[fx] = val[x] ^ val[y] ^ w;}
}
int main(){ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);cin >> n >> m;for(int i = 1; i <= m; i++){cin >> q[i].l >> q[i].r >> s;q[i].l--;if(s == "oven")q[i].t = 0;else if(s == "odd")q[i].t = 1;t.push_back(q[i].l);t.push_back(q[i].r);}sort(t.begin(), t.end());t.erase(unique(t.begin(), t.end()), t.end());n = t.size();for(int i = 1; i <= m; i++){q[i].l = lower_bound(t.begin(), t.end(), q[i].l)-t.begin()+1;q[i].r = lower_bound(t.begin(), t.end(), q[i].r)-t.begin()+1;}for(int i = 1; i <= n; i++)fa[i] = i, val[i] = 0;for(int i = 1; i <= m; i++){int fx = find(q[i].l);int fy = find(q[i].r);if(fx == fy){if(val[q[i].l]^val[q[i].r] != q[i].t){cout << i-1 << endl;return 0;}}elsemerge(q[i].l, q[i].r, q[i].t);}cout << m << endl;return 0;
}


食物链

题意:

三类动物 A,B,CA, B, CA,B,C , AAABBBBBBCCCCCCAAA

nnn 个动物,和 kkk 句话。每句话有两种描述:XXXYYY 是同类;XXXYYY

如果某一句话与前边真话冲突,则是假话,询问假话数目

解析:

333 倍并查集存关系,一倍存本身,二倍存食物,三倍存天敌

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define fi first
#define se second
const int maxn = 2e5+10;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;struct DSU{vector<int> fa;vector<int> rank;DSU(int n) : fa(n), rank(n){for(int i = 1; i <= n; i++)fa[i] = i;}int find(int x){return x == fa[x] ? x : fa[x] = find(fa[x]);}void merge(int x, int y){int fx = find(x);int fy = find(y);if(rank[fx] < rank[fy])fa[fx] = fy;else{fa[fy] = fx;if(rank[fx] == rank[fy])rank[fx]++;}}};
//1倍本身 2倍食物 3倍天敌 
int n, k, ans;
int main(){ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);cin >> n >> k;DSU dsu(3*n);int op, x, y;for(int i = 1; i <= k; i++){cin >> op >> x >> y;if(x > n || y > n){ans++;continue;}if(op == 1){if(dsu.find(x)==dsu.find(y+n) || dsu.find(x)==dsu.find(y+2*n)){ans++;continue;}dsu.merge(x, y);dsu.merge(x+n, y+n);dsu.merge(x+2*n, y+2*n);}else{if(x == y){ans++;continue;}if(dsu.find(x)==dsu.find(y) || dsu.find(x+2*n)==dsu.find(y)){ans++;continue;}dsu.merge(x, y+2*n);dsu.merge(x+n, y);dsu.merge(x+2*n, y+n);}}cout << ans << endl;return 0;
}

http://www.ppmy.cn/news/40375.html

相关文章

SD-WAN基本介绍

一、SD-WAN是什么&#xff1f;它能为我们带来什么&#xff1f; SD-WAN&#xff0c;即软件定义广域网络&#xff0c;是将SDN技术应用到广域网场景中所形成的一种服务。这种服务用于连接广阔地理范围的企业网络、数据中心、互联网应用及云服务&#xff0c;旨在帮助用户降低广域网…

NFS介绍

NFS简介 NFS&#xff08;Network File System&#xff09;是一种分布式文件系统&#xff0c;可在不同的机器之间共享文件。它最初是由Sun公司开发的&#xff0c;现在已成为一种标准的网络文件系统。NFS将网络上的一个目录挂载到另一个机器上&#xff0c;使得另一个机器可以访问…

Hive了解

目录 1.1 什么是Hive 1.2 Hive发展历程 1.3 Hive架构原理 1.1 什么是Hive 1&#xff09;Hive简介 Hive是由Facebook开源&#xff0c;基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张表&#xff0c;并提供类SQL查询功能。 那为什么会有Hive呢&a…

希尔排序的简单理解

详细描述 希尔排序又称为缩小增量排序&#xff0c;主要是对序列按下标的一定增量进行分组&#xff0c;对每组使用直接插入排序算法排序&#xff1b;随着增量逐渐减小&#xff0c;每组包含的关键字越来越多&#xff0c;当增量减至 1 时&#xff0c;整个文件恰被分成一组&#x…

Docker配置DL envs教程

Docker容器与镜像的区别 Docker镜像类似于虚拟镜像&#xff0c;是一个只读的文件&#xff0c;包括进程需要运行所需要的可执行文件、依赖软件、库文件、配置文件等等。 而容器则是基于镜像创建的进程&#xff0c;可以利用容器来运行应用。 总结来说&#xff0c;镜像只读&#…

Linux_vim编辑器

Vi编辑器是所有Unix及Linux系统下标准的编辑器&#xff0c;类似于windows系统下的notepad&#xff08;记事本&#xff09;编辑器&#xff0c;由于在Unix及Linux系统的任何版本&#xff0c;Vi编辑器是完全相同的&#xff0c;因此可以在其他任何介绍vi的地方都能进一步了解它&…

MATLAB算法实战应用案例精讲-【智能优化算法】强度帕累托进化算法 2 (SPEA2)(附MATLAB代码实现)

目录 前言 算法原理 算法思想 基于SPEA2的改进算法 原始 K 近邻方法

ios native 接入穿山甲sdk

【记录】穿山甲广告iOS版SDK接入记录_ios 集成穿山甲_sanjieshenwu1987的博客-CSDN博客 1、pod导入外部文件&#xff1b; 2、appDelegate文件中 3、 代码文件 class AskViewController: UIViewController,BUNativeExpressRewardedVideoAdDelegate{ 增加协议代理 4、广告加…