CDOJ 1070 秋实大哥打游戏

秋实大哥打游戏

limit 1s,75535KB


”也许人生就是游戏,你却执意耕耘着春秋。” —— 秋实大哥叹道。
秋实大哥是一个喜欢玩游戏的人,相较于其他种类的游戏,秋实大哥更喜欢自由开放的沙盒游戏,尤其是minecraft。
现在,秋实大哥发现了N个独立的小岛(编号1,2,3.....N),于是他要把这些小岛连起来。
每一次,秋实大哥会选择两个不同的小岛x(x是所在集合的中心)和y(y不一定是集合的中心),如果小岛x和小岛y不在一个集合里,就建立一条距离为|x−y| mod 1000的边,
把这两片小岛合并为一个新的集合,中心为y
原来所在的集合中心。
但,秋实大哥想实时知道某一个小岛距当前所在集合中心的距离。由于秋实大哥忙着过节,所以他想请你帮忙。


Input

第一行有一个整数N
表示小岛的个数。

接下来有若干行,每一行为以下两种操作中的一种:

I x y : 表示秋实大哥想要在x和y之间建立一条边。

E x : 询问x到当前集合中心的距离。

输入以一个大写字母O结束。

1≤N≤100000,操作数≤200000。


output

对于每一次询问,输出一个整数,即x到当前集合中心的距离,占一行。


sameple

input

3
I 1 2
E 1
I 3 1
E 3
O


output

1
3


题解

我校大神说这个叫做带权并查集——智障还没学过(ノ=Д=)ノ┻━┻

所以我的解法就是改动了一下并查集……

具体就是X,Y连通的时候,只改变X的par和dis的值,然后在询问的时候再进行根节点和距离的更新

感觉不大像最优解法,然而暂时就这样吧……


#include<stdio.h>
#include<algorithm>
#include<iostream>

using namespace std;
const int maxn=100000;

int par[maxn+5];
int dis[maxn+5];

int find(int x);
int update(int x);
inline int fab(int x);

int main(void)
{
	#ifdef ex
	freopen("in.txt","r",stdin);
	#endif
	
	int n;
	char s[5];
	int x,y;
	
	scanf("%d",&n);
	for (int i=1;i<=n;++i) par[i]=i;
	for (int i=1;i<=n;++i) dis[i]=0;
	
	while (true)
	{
		scanf("%s",s);
		if (s[0]=='O') break;
		if (s[0]=='I')
		{
			scanf("%d%d",&x,&y);
			update(y);
			int y_roof=find(y);
			if (x==y_roof) continue;
			else
			{
				par[x]=y_roof;
				dis[x]=dis[y]+fab(x-y)%1000;
			}
		}
		if (s[0]=='E') 
		{
			scanf("%d",&x);
			if (par[x]==par[par[x]]) printf("%d\n",dis[x]);
			else
			{
				update(x);
				find(x);
				printf("%d\n",dis[x]);
			} 
		}
	}
}

inline int fab(int x)
{
	if (x>0) return x;
	else return -x;
}
int find(int x)
{
	if (par[x]==x) return x;
	else
	{
		return par[x]=find(par[x]);
	}
}

int update(int x)
{
	if (par[x]==x) return 0;
	else
	{
		return dis[x]+=update(par[x]);
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值