首页 > 其他分享 >题解-Codeforces Round 805 (Div. 3) E. Split Into Two Sets

题解-Codeforces Round 805 (Div. 3) E. Split Into Two Sets

时间:2023-07-06 16:36:42浏览次数:54  
标签:int 题解 Into dsu Codeforces merge flag 集合 find

题解-Codeforces Round 805 (Div. 3) E. Split Into Two Sets

(原题链接)[Problem - E - Codeforces]

思路

知识点:种类并查集

网上关于种类并查集的教学已经很多,在此不赘述

在理解种类并查集时,很多文章会提到“敌人”,“朋友”的概念。而在不同的题目中,互为“敌人”,“朋友”的两个元素具体怎样处理是根据题目情况而确定。这里有个小技巧,就是考虑相同元素在题目中要如何操作,因为“自己和自己一定是朋友的关系”。而在本题中,比如有两个数字1,根据题目要求,同一个集合中不能有相同的数字,所以两个1一定会放在不同的集合中,也就是说,在本题中,互为朋友的两个元素一定放在不同集合中,互为敌人的元素一定放在相同集合中。

故据题意,每给出一个骨牌信息为a,b,由于这一个骨牌上的两个数字一定会放到同一个集合中,所以a,b我们应该看成敌人的关系。将a,b处理为敌人的关系用以下代码:

dsu.merge(a, b + n);
dsu.merge(b, a + n);

那什么情况下就一定不能按照题意分成两个集合了呢?因为a,b我们要处理成敌人的关系,但如果我们发现a,b已经是朋友关系了,明显出现了矛盾,这在本题中的含义就是:a和b在之前的处理中,它们应该属于不同集合,但是现在要把它们放入同一个集合,所以有了矛盾,这时就不能满足题意。

对不符题意的检验有以下两种方法:

  1. 在将a,b关联为敌人关系前检验a,b是否已经是朋友关系

    if (dsu.find(a) == dsu.find(b)) {
        flag = false;//不符题意
    } else {
        dsu.merge(a, b + n);
        dsu.merge(b, a + n);
    }
    
  2. 在程序结尾检验每个结点\(i\in [1,n]\),\(i+n\)是否与\(i\)联通,因为i+n初始时就定义为i的敌人,它们是不能被联通的。如果联通了,就是不符题意。

    for (int i = 1; i <= n; ++i) {
        if (deg[i] > 2) {
            flag = false;
            break;
        }
        if (dsu.find(i) == dsu.find(i + n)) {
            flag = false;
            break;
        }
    }
    

另外一点需要知道的是,每个数字出现的次数一定为2。这很好理解因为2n个数,每个数都在\(1\dots n\)的范围内,分成两个没有重复数字的集合的话,只能是两个集合都是\({1,2,\dots ,n}\)。

AC代码

#include<bits/stdc++.h>
using namespace std;
using i64 = long long;

class DSU {
public:
	vector<int> f;
	int n;

	DSU(int _n) : n(_n) {
		f.resize(n);
		iota(f.begin(), f.end(), 0);
	}

	int find(int x) {
		int r = x;
		while (r != f[r]) {
			r = f[r] = f[f[r]];
		}
		return r;
	}

	bool merge(int x, int y) {
		int fx = find(x), fy = find(y);
		if (fx == fy) return false;
		f[fx] = fy;
		return true;
	}
};

void solve() {
	int n;
	cin >> n;
	DSU dsu(2 * n);
	vector<int> deg(n);
	for (int i = 0; i < n; ++i) {
		int a, b;
		cin >> a >> b;
		--a; --b;
		deg[a]++;
		deg[b]++;
		dsu.merge(a, b + n);
		dsu.merge(b, a + n);
	}
	bool flag = true;
	for (int i = 0; i < n; ++i) {
		if (deg[i] > 2) {
			flag = false;
			break;
		}
		if (dsu.find(i) == dsu.find(i + n)) {
			flag = false;
			break;
		}
	}
	if (flag) cout << "YES\n";
	else cout << "NO\n";
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int t;
	cin >> t;

	while (t--) {
		solve();
	}

	return 0;
}

总结

这道题其实还有其它方法解决。如果使用种类并查集的话,有一个容易混淆的点,就是要分清并查集的联通以及题目中同一个集合的数字。因为在种类并查集中,两个结点联通说明它们是“朋友”关系,但在本题中,最终分到同一个集合中的结点两两之间是敌人的关系,也就是它们在并查集中应该是不连通的。

标签:int,题解,Into,dsu,Codeforces,merge,flag,集合,find
From: https://www.cnblogs.com/NonName/p/17532527.html

相关文章

  • 【补题记录】 Codeforces Round 797 (Div. 3) F Shifting String(置换环)
    CodeforcesRound797(Div.3)FShiftingString思路:根据这个排列进行替换的操作可以往置换环考虑,就是对于每一段字串,它的变换都是有规律的,经过一定的操作之后都会回到原点,可以想象转化成图上问题。参考ygg的题解,直接用链表模拟这个转化的过程,然后暴力计数,因为要满足所有点都......
  • CodeChef Cutting Plants难题题解
    STL-CodeChefCuttingPlants题解单调队列哦我要造福后人,因为题解太jb难找了题意:2个操作找一段l-r区间,取其<=最小值的任意高度,记为h将l-r变为h时间复杂度暂时归为n吧思路:(思路应该很容易跟上)最特殊的:L=R,来嘛我每个独自减那为什么会有-1呢涨不回去呗(bi>ai)现在关键在......
  • 【DSY 4484】矩阵 题解(带限错排)
    DSY传送门。(带限制)错排问题。神仙题。Solution根据题目的问法,发现我们只想统计比给定矩阵\(A\)小的矩阵,记这个矩阵为\(B\)。显然,\(B\)的第\(i\)行一定从某个位置开始小于\(A\)的第\(i\)行,且前面的内容和\(A\)都是一样的。所以我们只需要枚举这个“开始变小”......
  • Codeforces Round #222 (Div. 1) B - Preparing for the Contest
    先二分,输入排序,然后对于确定的天数,贪心判断是否可行。#include<iostream>#include<queue>#include<stack>#include<map>#include<set>#include<bitset>#include<cstdio>#include<algorithm>#include<cstring>#include<......
  • 「NOIP 模拟赛 20230705」T2-序列删数问题 题解
    题面Natsuzora有一个长度为\(n\)的排列\(a_1,a_2,\ldots,a_n\),他想要将序列中的\(m\)个数删除。删除数字需要使用到“魔法工具”,其也有\(m\)种,其中第\(i\)种魔法工具能够将排列中任意一个的长度为\(l_i\)的区间中最大的数删除。每个魔法工具最多只能使用\(1\)次。......
  • 【后缀自动机】Codeforces Round #305 (Div. 1) E. Mike and Friends
    对所有的串加特殊字符隔开,单串建立后缀自动机。然后将每个的fa边反向建树,对树dfs得到dfs序,对dfs序建立线段树。询问离线,每个询问拆成1-(l-1)和1-r。。。按端点排序,然后每次加入线段树,查询k对应的节点的子树和。。。#include<iostream>#include<queue>#include<stack>#include......
  • codeforces 540D - Bad Luck Island
    记忆化搜索...#include<iostream>#include<queue>#include<stack>#include<map>#include<set>#include<bitset>#include<cstdio>#include<algorithm>#include<cstring>#include<climits>#include......
  • 洛谷P9025题解
    P9025题解简化题意求一个值\(c\)使得\[\sum_{i=1}^nw_i(\left|c-p_i\right|-d_i)\]最小化(注意题目中\(w_i\)表示每移动一米需要\(w_i\)秒)思路首先我们令选择\(c\)位置的总用时为\(f(c)\)显然,我们可以把它分成两边来看在\(c\)左边的人:\[f(c)=\sum_{p_i+d_......
  • 题解:【AT icpc2015summer day2-G】 Escape
    题目链接目前AT的最优解。树的话就是根叶链的最大点权和路径,DP随便搞。考虑扩展到图上,反复删除掉所有度数为\(1\)的节点,显然剩下的东西是可以全部取完的,因为它的形态类似于菊花套环,且末端必定为环。将这部分缩起来再跑上面的DP就好了。事实上两部分可以同时进行,一个bfs......
  • Springboot No bean named 'XXXXX' available 问题解决
    一、问题描述近日在工作中遇见了一个bug,后端程序频频报错Nobeannamed'XXXXX'available。对比同类程序文件,没有发现有任何特殊之处。在网上搜索方法基本上就是扫描包配置、注解问题、路径问题等,皆不能解决我的问题。排查问题是发现出现问题的类命名不符合驼峰规范,按照这个......