璟雯院

珺璟如晔,雯华若锦

用户工具

站点工具


icpc:problems:usaco21jan_dance_mooves_s
problems
名称Dance Mooves S
题目编号USACO21JAN_S1
题目链接luogu.com.cn/…
来源USACO
算法分类并查集, 图论
难易程度一般般

Dance Mooves S

想法

由题目大意可以知道:

  1. 每分钟会交换两个位置。
  2. n*k轮会恢复原样。

假设现在有两个点A与B,A点在k次交换后从 x 走到了 y ,B点在k次交换后从 z 走到了 x。可以很明显的知道再经过k次交换后,B点会从x走到y。那A经过的点也一定会被B经过,B包含了A。

所以可以通过这个关系(起点与终点)来重新建立一张图,每个点会有一个出边与入边,出边指向经过k次交换后的终点,入边为经过k次交换后走到该点的点。这个图存在n个点,n条边,且每个点出度入度均为1,故这个图只有环,或自环。

在同一环内的牛,所有牛经过的位置互相均可以访问到。使用并查集来维护该环,并记录每头牛能经过的路径,最后汇总起来。

代码实现

#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
 
const int N = 1e5+10;
set<int>vis[N], ans[N];
int F[N], sit[N], n, k;
 
int find(int x)
{
	return x == F[x] ? x : F[x] = find(F[x]);
}
 
int main()
{
	int x, y;
	cin >> n >> k;
	for(int i=1; i<=n; i++) { F[i] = i; sit[i] = i; vis[i].insert(i); }
	for(int i=1; i<=k; i++)
	{
		cin >> x >> y;
		swap(sit[x], sit[y]);
		vis[sit[x]].insert(y);
		vis[sit[y]].insert(x);
	}
	for(int i=1; i<=n; i++)
	{
		x = find(i); y = find(sit[i]);
		if(x != y) F[y] = x;
	}
 
	for(int i=1; i<=n; i++)
	{
		x = find(i);
		vis[x].insert(vis[i].begin(), vis[i].end());
	}
 
	for(int i=1; i<=n; i++)
		cout << vis[find(i)].size() << '\n';
 
	return 0;
}
/app/www/public/data/pages/icpc/problems/usaco21jan_dance_mooves_s.txt · 最后更改: 2023/03/11 10:44 由 温婕莺