POJ1962 Corporative Network 并查集

题意:

给定原来孤立的n个点。

然后进行两种操作:

E i:查询第i个点到它的根节点的距离(mod1000),孤立点的根节点是它自己。

I i j:将节点i接到节点j上。

思路:

并查集。但是要申请一个数组来代表每个点的权值,优化一下时间,否则TLE。

其实优化的本质按标准范例说明如下:

如果是没有权值的并查集构成的链为3->1->2->4这样。查询3的时候都从3到4要运算3次加法,显然耗时。

优化之后:刚开始是3->1,dis[3]=2,然后因为操作I 1 2得1->2,且dis[1]=|1-2|mod1000=1,的时候将3->1也转化为3->2,同时dis[3]=dis[3]+dis[1];2是根节点所以dis[2]=0.

即本质是将每个并查集构成的树都转化为一个深度=1,即每个节点都和它的根节点直接相连的树,因为如果这个树恶化成一条链,这条链的耗时很大。

挺好的一道题目。

#include<iostream>
#include<algorithm>
#define max(a,b) (a>b?a:b)
#define abs(a) ((a)>0?(a):-(a))
#define min(a,b) (a<b?a:b)
using namespace std;
const int N=20005;
int n;
int root[N];
int dis[N];
char oper;
int query(int x)
{
	if(root[x]==x)
	{
		return x;
	}
	int ret=query(root[x]);
	dis[x]=(dis[x]+dis[root[x]]);//要在query函数之后,因为每次query函数都会更新dis值.
	root[x]=ret;
	return ret;
}
int main()
{
	int cases;
	scanf("%d",&cases);
	while(cases--)
	{
		memset(dis,0,sizeof(dis));
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			root[i]=i;
		while(getchar(),scanf("%c",&oper),oper!='O')
		{
			int x,y;
			if(oper=='E')
			{
				scanf("%d",&x);
				query(x);
				printf("%d\n",dis[x]);
			}
			else
			{
				scanf("%d%d",&x,&y);
				root[x]=y;
				dis[x]=(abs(x-y))%1000;
			}
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值