秋实大哥打游戏
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]);
}
}