cdoj 2015数据结构专题:H - 秋实大哥打游戏

”也许人生就是游戏,你却执意耕耘着春秋。” —— 秋实大哥叹道。

秋实大哥是一个喜欢玩游戏的人,相较于其他种类的游戏,秋实大哥更喜欢自由开放的沙盒游戏,尤其是minecraft

现在,秋实大哥发现了 N 个独立的小岛(编号 1,2,3.....N ),于是他要把这些小岛连起来。

每一次,秋实大哥会选择两个不同的小岛 x x 是所在集合的中心)和 y y 不一定是集合的中心),如果小岛 x 和小岛 y 不在一个集合里,就建立一条距离为 |xy|   mod   1000 的边,

把这两片小岛合并为一个新的集合,中心为 y 原来所在的集合中心。

但,秋实大哥想实时知道某一个小岛距当前所在集合中心的距离。由于秋实大哥忙着过节,所以他想请你帮忙。

Input

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

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

I x y : 表示秋实大哥想要在xy之间建立一条边。
E x : 询问x到当前集合中心的距离。

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

1N100000 ,操作数 200000

Output

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

Sample input and output

Sample Input Sample Output
3
I 1 2
E 1
I 3 1
E 3
O
1
3

用并查集实现。

初始化每个小岛独立,并建一个数组记录各个小岛到并查集中指向小岛的距离。新加入一条边时,对x片区的小岛,其中心会改变,所以所有小岛到中心的距离都会改变,但是询问不一定问到。可以做一个懒操作,只将x片区小岛中的x和中心改变,将中心指向xx指向y,两个距离也相应改变。当询问某个小岛的中心时,除了路径压缩,还要将距离更新为到中心的距离。最后询问某小岛到中心的距离时,进行一次更新即可得到答案。


#include <iostream>
#include <cstdio>
#include <cstdlib>

using namespace std;

int dist[100000] = {0},set[100000];

int father(int k)
{
    if(k == set[k])
        return k;
    int fx = father(set[k]);
    dist[k] += dist[set[k]];
    set[k] = fx;
    return set[k];
}

void uni(int x, int y)
{
    int fx = father(x), fy = father(y);
    if(fx == fy)
        return;
    else
    {
        set[fx] = x;
        dist[fx] = dist[x];
        set[x] = y;
        dist[x] = abs(x-y) % 1000;
        return;
    }
}

void build(int n)
{
    for(int i = 1; i <= n; i++)
        set[i] = i;
}

int main()
{
    int n;
    char c[2];
    scanf("%d",&n);
    build(n);
    while(scanf("%s",c) && c[0] != 'O')
    {
        if(c[0] == 'I')
        {
            int x,y;
            scanf("%d%d",&x, &y);
            uni(x,y);
        }
        else
        {
            int l;
            scanf("%d",&l);
            father(l);
            printf("%d\n",dist[l]);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值