P1653 猴子

猴子!好可爱!不过好难!


问题

给你许多只猴子,每一个时间段他们放手,问猴子掉落的时间。

分析

注意:这里的猴子抓猴子,不一定要手拉手,拽别人尾巴照样不会掉下去!

所以其实是一个无向图的连通问题。

每一个联通分支,答案一定是相同的。

所以可以考虑并查集来维护。而这里是一个带权的并查集。

放手是摧毁连通,想想都是几乎不可能做到的事情。

所以正难则反,我们考虑离线回答问题,从\(m-1\)\(0\)时间段倒着算答案。

那么就是一个添加连通的问题了,直接并查集merge即可。

我们维护ans数组,表示猴子掉下去的时间。

1号猴子吊在树上,怎么都不会掉,所以\(ans[1] = INF\)

首先当然要连上\(m\)时间段中,还剩下的边。

然后就可以直接逆序合并集合,回答问题了。

如何维护ans?

这也许是最难的地方了。如果没有学过带权并查集的话,绝对想不出来。我就想不出来

给出代码:

int find(int x)
{
	if(fa[x] == x) return x;
	int temp = find(fa[x]);
	ans[x] = std::min(ans[x], ans[fa[x]]);
	return fa[x] = temp;
}

这个东西什么意思?

一个点的ans,是这个联通分支中最小的ans。

注意一定要先递归,不然从下面弄上去是错的。

先递归的话,先执行的是第二层、第三层,以此类推到叶子。

如果不懂的话就死记吧。。。

其他的东西都是细节,说不了。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>

const int maxn = 200005, maxm = 400005, INF = 0x3f3f3f3f;
int n, m;
struct Node//the situation of loosing hand
{
	int u, hand;
} s[maxm];
int G[maxn][2];
bool b[maxn][2];
int ans[maxn];
int fa[maxn];
int read()
{
	int ans = 0, s = 1;
	char ch = getchar();
	while(ch > '9' || ch < '0')
	{
		if(ch == '-') s = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9')
	{
		ans = ans * 10 + ch - '0';
		ch = getchar();
	}
	return s * ans;
}
int find(int x)
{
	if(fa[x] == x) return x;
	int temp = find(fa[x]);
	ans[x] = std::min(ans[x], ans[fa[x]]);
	return fa[x] = temp;
}
void merge(int x, int y, int k)
{
	x = find(x), y = find(y);
	if(x != y)
	{
		if(x == 1) fa[y] = x, ans[y] = k;
		else fa[x] = y, ans[x] = k;
	}
}
int main()
{
	n = read(), m = read();
	for(int i = 1; i <= n; i++)
	{
		fa[i] = i;
		G[i][0] = read(), G[i][1] = read();
	}
	for(int i = 0; i < m; i++)
	{
		s[i].u = read(), s[i].hand = read() - 1;
		b[s[i].u][s[i].hand] = true;
	}
	for(int i = 1; i <= n; i++)
	{
		for(int j = 0; j <= 1; j++)
		{
			if(!b[i][j] && G[i][j] != -1) merge(i, G[i][j], m);
		}
	}
	memset(ans, 0x3f, sizeof(ans));
	for(int i = m - 1; i >= 0; i--)
	{
		if(G[s[i].u][s[i].hand] != -1) merge(s[i].u, G[s[i].u][s[i].hand], i);
	}
	for(int i = 1; i <= n; i++)
	{
		find(i);
		if(ans[i] == INF) printf("-1\n");
		else printf("%d\n", ans[i]);
	}
	return 0;
}
posted @ 2018-06-29 21:54  Garen-Wang  阅读(292)  评论(0编辑  收藏  举报