P1196 [NOI2002]银河英雄传说(带权并查集)

这个题的题目背景很是宏大,什么宇宙战舰的都出来了。但细细一看,我们就会发现,这是带权并查集的题目,首先我们还是像之前在并查集中的操作一样,但在这里我们还是应该开数组来维护所要加的权值,两个战舰是否在同一个队列中好判断,关键是他们间的间隔,实际上就是他们的权值之和的绝对值再减一,代码如下

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7; 
int fa[maxn];
int va[maxn];//该点的权值
int num[maxn];//到父亲节点的距离当前队列的长度
int n,x,y;
char opt[maxn];
int fid(int x)
{
    if(x==fa[x])
    {
        return x;
    }
    int t=fa[x];
    fa[x]=fid(fa[x]);//路径压缩 
    va[x]+=va[t]; //回溯时注意要更新
    num[x]=num[t]; //x所在队列的长度就是父亲节点所在队列的长度
    return fa[x];
}
void united(int x,int y)
{
    int f1=fid(x);
    int f2=fid(y);
    if(f1==f2)
    {
        return;
    }
    fa[f1]=f2;//将x所在队列的对头加入y的队列
    va[f1]+=num[f2];//x所在队列的父节点的最新权值
    num[f1]+=num[f2];//更新当前队列的长度
    num[f2]=num[f1];
}
int check(int x,int y)//判断是否在同一集合中
{
    int f1=fid(x);
    int f2=fid(y);
    if(f1==f2)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
        va[i]=0;
        num[i]=1;
    } 
    for(int i=1;i<=n;i++)
    {
        scanf("%s",opt);
        if(opt[0]=='M')
        {
            scanf("%d%d",&x,&y);
            united(x,y);
        }
        else
        {
            scanf("%d%d",&x,&y);
            if(check(x,y))
            {
                printf("%d\n",abs(va[x]-va[y])-1);
            }
            else
            {
                printf("-1\n");
            }
        }
    }
    return 0;
} 

 

posted @ 2019-04-06 23:00  JBLee  阅读(139)  评论(0编辑  收藏  举报