zoj3261 并查集---略有变形

题意:有n个星球,每个星球有一定的power值,某些星球是直接或间接相连的。。。当某个星球想求助时会找到相连的里面的power值最大而且大于自己的一个星球。。。先在给定这些power值并给定两两相连的信息,然后又q个操作,destroy a b是删除a b直接相连的边(保证存在),query a求向谁求助,如果不能求助输出-1 。。。


这题是miaowu做的时候给我做的。。。

本来还没想法,他提醒的我哈。。比较巧妙的是先将相连信息和操作信息存下来,从后往前推就成了裸的并查集了。。。

但是存两两关系不大好存。。只能想到用vector存。。。(话说感觉理论上讲如果出变态数据的话是会超时的哈)。。。。

中间一个判断出错wa了几次。。。


代码:


#include<iostream>
#include<stdio.h>
#include<vector>
using namespace std;

const int N=50010;
int a[N], n, m, q, f[N], x1[N], y1[N], ans[N], ansn;
vector<int> ma[N];
char s[20];

int findset(int x)
{
	if(f[x]!=x)
		f[x] = findset(f[x]);
	return f[x];
}

void unionset(int x, int y)
{
	int fx = findset(x);
	int fy = findset(y);
	if(fx!=fy)
	{
		if(a[fx]>a[fy])
			f[fy] = fx;
		else if(a[fy]>a[fx])
			f[fx] = fy;
		else if(fx<fy)
			f[fy] = fx;
		else
			f[fx] = fy;
	}
}

int main()
{
	int i, j, k, x, y, tmp;
	vector<int>::iterator it;
	scanf("%d", &n);
	while(1)
	{
		for(i=0; i<n; i++)
			scanf("%d", &a[i]);
		scanf("%d", &m);

		for(i=0; i<m; i++)
		{
			scanf("%d%d", &x, &y);
			if(x>y)
				swap(x, y);
			ma[x].push_back(y);
		}
		scanf("%d", &q);
		for(i=0; i<q; i++)
		{
			scanf("%s", s);
			if(s[0]=='q')
			{
				scanf("%d", &y1[i]);
				x1[i] = -1;
			}
			else
			{
				scanf("%d%d", &x1[i], &y1[i]);
				if(x1[i]>y1[i])
					swap(x1[i], y1[i]);
				for(it=ma[x1[i]].begin(); it!=ma[x1[i]].end(); it++)
					if(*it==y1[i])
					{
						*it = -1;
						//break;
					}
			}
		}
		for(i=0; i<=n; i++)
			f[i] = i;
		for(i=0; i<n; i++)
		{
			for(it=ma[i].begin(); it!=ma[i].end(); it++)
				if(*it!=-1)
				{
					unionset(i, *it);
					//printf("%d %d..\n", i, *it);
				}
		}
		ansn = 0;
		for(i=q-1; i>=0; i--)
		{
			if(x1[i]==-1)
			{
				tmp = findset(y1[i]);
				if(a[tmp]!=a[y1[i]]) //这个地方原来写成了tmp!=y1[i]。。。wa了。。。
					ans[ansn++] = tmp;
				else
					ans[ansn++] = -1;
			}
			else
				unionset(x1[i], y1[i]);
		}
		for(i=ansn-1; i>=0; i--)
			printf("%d\n", ans[i]);

		for(i=0; i<n; i++)
			ma[i].clear();
		if(scanf("%d", &n)!=EOF)
			printf("\n");
		else
			break;
	}
	return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值