您的位置:首页 > 其它

CDOJ 1070 秋实大哥打游戏

2016-03-28 22:13 295 查看

秋实大哥打游戏

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]);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: