P6004 [USACO20JAN] Wormhole Sort S

更好的阅读体验

传送门

题目大意

Farmer JohnNN 头编号为 1N1 \ldots N 的奶牛(1N1051 \leq N \leq 10^5),分散在牛棚中 NN 个编号为 1N1 \ldots N 的不同位置,奶牛 ii 位于位置 pip_i

MM 个编号为 1M1 \ldots M 的虫洞(1M1051 \leq M \leq 10^5 ),其中虫洞 ii 双向连接了位置 aia_ibib_i,宽度为 wiw_i

在任何时刻,两头位于一个虫洞两端的奶牛可以选择通过虫洞交换位置。奶牛们需要反复进行这样的交换,直到奶牛 ii 位于位置 ii

问使用的虫洞宽度的最小值的最大值是多少。

如果奶牛们不需要用任何虫洞来排序,输出 1−1

解题思路

首先可以发现如果能够成功交换,即对于 i=1n\sum\limits_{i=1}^{n} 奶牛 ii 能到达点 ii,则位置 ii 必与位置 aia_i 连通,用并查集判断即可。

方法一

对于求最小值的最大值,显然可以二分答案 midmid,判断在仅保留宽度 mid\ge mid 的边时,奶牛 ii 能否到达点 aia_i

方法二

可以先按照宽度从大到小进行排序,再循环遍历每一条边 (u,v)(u,v),并将这条边添加并查集里,判断当前的图(指的是并查集)中,所有奶牛 ii 能否到达点 aia_i

AC CODE

方法一

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

struct Fastio
{
	template <typename T>
	inline Fastio operator>>(T &x)
	{
		x = 0;
		char c = getchar();
		while (c < '0' || c > '9')
			c = getchar();
		while (c >= '0' && c <= '9')
			x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
		return *this;
	}
	inline Fastio &operator<<(const char c)
	{
		putchar(c);
		return *this;
	}
	inline Fastio &operator<<(const char *str)
	{
		int cur = 0;
		while (str[cur])putchar(str[cur++]);
		return *this;
	}
	template <typename T>
	inline Fastio &operator<<(T x)
	{
		if (x == 0)
		{
			putchar('0');
			return *this;
		}
		if (x < 0) putchar('-'), x = -x;
		static int sta[45];
		int top = 0;
		while (x) sta[++top] = x % 10, x /= 10;
		while (top) putchar(sta[top] + '0'), --top;
		return *this;
	}

} io;

int n, m, ans;

int fa[_];

int flag;

int a[_];

struct abc
{
	int u, v, w;
}e[_];

int mmax;

bool cmp(abc a, abc b)
{
	return a.w > b.w;
}

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

void merge(int x, int y)
{
	int f1 = find(x);
	int f2 = find(y);
	if(f1 != f2) fa[f2] = f1;
}

bool check(int x)
{
	for(int i = 1; i <= n; ++i) fa[i] = i;
	for(int i = 1; i <= m; ++i)
		if(e[i].w >= x) merge(e[i].u, e[i].v);
	for(int i = 1; i <= n; ++i)
		if(find(i) != find(a[i])) return false;
	return true;
}

signed main()
{
	io >> n >> m;
	for(int i = 1; i <= n; ++i)
	{
		io >> a[i];
		if(a[i] != i) flag = 1;
		fa[i] = i;
	}
	for(int i = 1; i <= m; ++i)
		io >> e[i].u >> e[i].v >> e[i].w;
	if(!flag)
	{
		io << "-1" << "\n";
		return 0;
	}
	int l = 0, r = INT_MAX;
	while(l <= r)
	{
		int mid = (l + r) >> 1;
		if(check(mid))
		{
			ans = mid;
			l = mid + 1;
		}
		else r = mid - 1;
	}
	io << ans << "\n";
	return 0;
}

方法二

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

struct Fastio
{
	template <typename T>
	inline Fastio operator>>(T &x)
	{
		x = 0;
		char c = getchar();
		while (c < '0' || c > '9')
			c = getchar();
		while (c >= '0' && c <= '9')
			x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
		return *this;
	}
	inline Fastio &operator<<(const char c)
	{
		putchar(c);
		return *this;
	}
	inline Fastio &operator<<(const char *str)
	{
		int cur = 0;
		while (str[cur])putchar(str[cur++]);
		return *this;
	}
	template <typename T>
	inline Fastio &operator<<(T x)
	{
		if (x == 0)
		{
			putchar('0');
			return *this;
		}
		if (x < 0) putchar('-'), x = -x;
		static int sta[45];
		int top = 0;
		while (x) sta[++top] = x % 10, x /= 10;
		while (top) putchar(sta[top] + '0'), --top;
		return *this;
	}

} io;

int n, m, ans;

int fa[_];

int flag;

int a[_];

struct abc
{
	int u, v, w;
}e[_];

int mmax;

bool cmp(abc a, abc b)
{
	return a.w > b.w;
}

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

signed main()
{
	io >> n >> m;
	for(int i = 1; i <= n; ++i)
	{
		io >> a[i];
		if(a[i] != i) flag = 1;
		fa[i] = i;
	}
	for(int i = 1; i <= m; ++i)
		io >> e[i].u >> e[i].v >> e[i].w;
	if(!flag)
	{
		io << "-1" << "\n";
		return 0;
	}
	sort(e + 1, e + m + 1, cmp);
	for(int i = 1, j = 1; i <= m; ++i)
	{
		int x1 = find(e[i].u), x2 = find(e[i].v);
		if(x1 != x2) fa[x2] = x1;
		while(find(j) == find(a[j]))
		{
			j++;
		}
		if(j > n)
		{
			io << e[i].w << "\n";
			return 0;
		}
	}
	return 0;
}
posted @ 2021-08-10 18:15  蒟蒻orz  阅读(4)  评论(0编辑  收藏  举报  来源