带权并查集 NOI 2002 银河英雄传说

题意:有 n n 艘战舰,一开始排成一行,第i号战舰在第 i i 列,两种操作:
1.Mij 表示将第 i i 号战舰所在的整个战舰队列,作为一个整体(头在前尾在后)接至第j号战舰所在的战舰队列的尾部。
2.Cij 表示询问第 i i 号战舰与第j号战舰当前是否在同一列中,如果在同一列中,那么它们之间有多少战舰。

这题一看就是并查集,但怎么维护两艘战舰之间有多少战舰呢?这里就要使用带权并查集了。 val[i] v a l [ i ] 表示飞船 i i 到其所在队列队头的距离(类似一个前缀和的东西),num[i]表示以 i i <script type="math/tex" id="MathJax-Element-739">i</script>为队头的队列的飞船数量。具体说明看代码

#include<bits/stdc++.h>
using namespace std;
int val[1001000],f[1001000],num[1001000];
int find(int x)
{
    if(x==f[x])
        return x;
    if(x!=f[x])
    {
        int g=f[x];
        f[x]=find(f[x]);
        val[x]+=val[g];//更新当前节点到根的距离
        return f[x];
    }
}
int merge(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
    {
        f[fx]=fy;
        val[fx]=val[fy]+num[fy];//更新合并之后fx到队头的距离
        num[fy]+=num[fx];//更新以fy为队头的队列的飞船数量
        num[fx]=0;//以fx为队头的队列数量清零
    }
}
char s[5];
int main()
{
    int t;
    cin>>t;
    for(int i=1;i<=35000;i++) 
    {
        f[i]=i;
        num[i]=1;
    }
    while(t--)
    {
        scanf("%s",s+1);
        if(s[1]=='M')
        {
            int a,b;
            scanf("%d%d",&a,&b);
            merge(a,b);
        }
        if(s[1]=='C')
        {
            int a,b;
            scanf("%d%d",&a,&b);
            if(find(a)!=find(b))
                cout<<"-1"<<endl;
            else
                cout<<abs(val[a]-val[b])-1<<endl;       
        }
    }
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值