首页 > 其他分享 >【并查集+dfs】codeforces 1833 E. Round Dance

【并查集+dfs】codeforces 1833 E. Round Dance

时间:2024-10-18 21:36:00浏览次数:7  
标签:1833 dsu leq Dance 查集 dfs find int 节点

题意

输入一个正整数 \(T(1 \leq T \leq 10^4)\),表示接下来输入 \(T\) 组测试用例,对于每一个测试用例:
第一行,输入一个正整数 \(n(2 \leq n \leq 2 * 10^5)\)
第二行,输入 \(n\) 个正整数 \(a_i(1 \leq a_i \leq n)\),表示节点 \(i\) 到节点 \(a_i\) 存在一条有向边,保证无自环

这 \(n\) 个节点共同围成若干个环,特殊情况除只有两个节点的环以外,每个节点左右各有一个相邻节点。且每个环至少会有 \(2\) 个节点。
问这 \(n\) 个节点最少和最多各能组成多少个环?

题解

建立有向边后,必定可以划分为若干张(弱)连通图,连通图若整张图就是个环且节点数大于 \(2\),则无法再插入更多元素,其他情况均可以与节点数大于等于3的环以外的(弱)连通图进行结合。

总结为:大二有环即为环,否则均为一条链

参考代码

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
using namespace std;

constexpr int N = 2e5 + 7;
int T = 1, n;
int a[N], in[N], dsu[N], sz[N];
bool vis[N];

int find(int x) { return x == dsu[x] ? x : dsu[x] = find(dsu[x]); }

void merge(int x, int y) { 
	int fx = find(x), fy = find(y);
	if (fx == fy) return ;
	dsu[fx] = fy; 
	sz[fy] += sz[fx];
}

void solve() {
	int cnt1 = 0, cnt2 = 0;
	cin >> n;
	for (int i = 1; i <= n; ++ i) {
		cin >> a[i];	
		dsu[i] = i;
		sz[i] = 1;
		in[i] = 0;
		vis[i] = false;
	}
	auto dfs = [&](auto &&dfs, int x) -> void {
		vis[x] = true;
		in[a[x]] ++;
		merge(x, a[x]);
		if (!vis[a[x]]) dfs(dfs, a[x]);
	};
	unordered_map<int, bool> ump;
	for (int i = 1; i <= n; ++ i) if (!vis[i]) dfs(dfs, i);
	for (int i = 1; i <= n; ++ i) {
		bool b = in[i] == 2;
		int ro = find(i);
		if (ump.find(ro) == ump.end()) ump[ro] = b;
		else ump[ro] = b || ump[ro];
	}
	for (auto &it: ump) (it.second || sz[it.first] < 3 ? cnt1 : cnt2) ++;
	cout << cnt2 + (cnt1 > 0) << ' ' << cnt1 + cnt2 << '\n';
}

int main() {
	IOS
	cin >> T;
	while (T --) solve();
	return 0;
}

标签:1833,dsu,leq,Dance,查集,dfs,find,int,节点
From: https://www.cnblogs.com/RomanLin/p/18474273

相关文章

  • 模板-并查集DSU
    版本1:路径压缩。structDSU{ std::vector<int>fa; voidinit(intn){ fa.resize(n+1); std::iota(fa.begin(),fa.end(),0); } intleader(intx){ while(x!=fa[x]){ fa[x]=leader(fa[x]); } returnfa[x]; } voidjoin(intx,inty){ x......
  • 并查集
    836.合并集合一共有n个数,编号是1∼n,最开始每个数各自在一个集合中。现在要进行mm个操作,操作共有两种:Mab,将编号为a和b的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;Qab,询问编号为a和b的两个数是否在同一个集合中;输入格式第一行输入......
  • Leetcode 839. 相似字符串组【附并查集模板】
    1.题目基本信息1.1.题目描述如果交换字符串X中的两个不同位置的字母,使得它和字符串Y相等,那么称X和Y两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。例如,”tars”和“rats”是相似的(交换0与2的位置);“rats”和“arts”也是相似的,但是“s......
  • 并查集
    1.并查集每次合并两个不相交集合,或者询问两个元素是否在同一个集合里。洛谷P1197[JSOI2008]星球大战给一张图,每次删掉一个点及相连的边,求剩下的图中的联通块数。我们倒着从空图往回做,就变成了加边求联通块数的问题。洛谷P1525[NOIP2010提高组]关押罪犯有一张图,边......
  • 深度优先搜索与并查集
    一:深度优先搜索示例1题目链接:886.可能的二分法-力扣(LeetCode)首先可以构建一个图的邻接表表示,然后使用深度优先搜索(DFS)算法来检查图是否可以二分。如果图可以二分,则返回True;否则返回False。具体步骤如下:构建图:使用一个列表 graph 来存储每个节点的邻接节点。初始化......
  • Codeforces2020D Connect the Dots(观察 + 并查集 + 差分)
    题意多组数据。数轴上有\(n\)个点,编号为\(1\simn\),对这些点做$m$次操作。每次操作给出三个整数\(a_i(1\lea_i\len)\\\d_i(1\led_i\le10)\\\k_i(0\lek_i\len)\)。将点\(a_i,a_i+d_i,a_i+2\timesd_i,a_i+3\timesd_i,\cdot\cdot\cdo......
  • 《The Graceful Dance of Fog》
    《TheGracefulDanceofFog》 Fog,likeanetherealwhitesilk,quietlyblanketstheexpanseofheavenandearth.Itresemblesamysteriousdancer,movinginsilenceandenshroudingthewholeworldinitsdreamlikeembrace. "Thefogentwinesaround......
  • 食物链(并查集)
    一开始默认为0,如果有捕食关系调整d[x]#include<bits/stdc++.h>usingnamespacestd;#definexfirst#defineysecondtypedefpair<int,int>PII;typedeflonglongll;typedefunsignedlonglongull;typedefunsignedintuint;typedefvector<string>VS;ty......
  • [CEOI1999] Parity Game(并查集)
    方法1:带权路径维护本题核心:[a,b]之间有奇数个1转换为s[a-1]^s[b]=1,从而转向并查集#include<bits/stdc++.h>usingnamespacestd;#definexfirst#defineysecondtypedefpair<int,int>PII;typedeflonglongll;typedefunsignedlonglongull;typedefunsignedint......
  • [NOI2002] 银河英雄传说(带权并查集)
    带权并查集稍微注意下细节、#include<bits/stdc++.h>usingnamespacestd;#definexfirst#defineysecondtypedefpair<int,int>PII;typedeflonglongll;typedefunsignedlonglongull;typedefunsignedintuint;typedefvector<string>VS;typedefve......