[Luogu 1196] NOI2002 银河英雄传说

[Luogu 1196] NOI2002 银河英雄传说


话说十六年前的 NOI 真简单。。。

我一开始还把题看错了…

题意:一群人,每个人各自成一队,每次命令让两队首位相接合成一队,每次询问问你某两个人之间有几个人。

容易想到合并用并查集来实现。

至于计数,\(\mathrm{sum}_i\) 表示 \(i\) 到队首有几个人(如果 \(i\) 在队首,\(\mathrm{sum}_i = 0\));

\(\mathrm{num}_i\) 表示以 \(i\) 为队首的队伍有几个人(如果 \(i\) 不在队首, \(\mathrm{num}_i = 0\) )。

并查集 Find 的时候,递归回溯时更新 \(\mathrm{sum}_i\),不断加上其父亲的 \(\mathrm{sum}\)

合并的时候,首先建立父子关系,然后更新 \(\mathrm{num}\)\(\mathrm{sum}\),具体见代码中的 Merge 函数。

询问的话,如果两个人在同一队列中,两人的距离为他们到队首的距离差减一,即 \(|\mathrm{sum}_x - \mathrm{sum}_y| - 1\)

完结撒花,还是挺好写的 qwq


#include <cstdio>
#include <cstdlib>
const int MAXN=30010;
int n;
class UFS
{
    private:
        int f[MAXN],sum[MAXN],num[MAXN];
        int Find(int x)
        {
            if(x==f[x])
                return x;
            int t=Find(f[x]);
            sum[x]+=sum[f[x]];
            return f[x]=t;
        }
    public:
        UFS(void)
        {
            for(int i=1;i<=30000;++i)
            {
                f[i]=i;
                sum[i]=0;
                num[i]=1;
            }
        }
        void Union(int x,int y)
        {
            int a=Find(x),b=Find(y);
            f[a]=b;
            sum[a]+=num[b];
            num[b]+=num[a];
            num[a]=0;
        }
        void Query(int x,int y)
        {
            if(Find(x)^Find(y))
                puts("-1");
            else
                printf("%d\n",abs(sum[x]-sum[y])-1);
        }
}S;
int main(int argc,char** argv)
{
    scanf("%d",&n);
    for(int x,y;n--;)
    {
        char opt;
        scanf("\n%c %d %d",&opt,&x,&y);
        if(opt=='M')
            S.Union(x,y);
        else
            S.Query(x,y);
    }
    return 0;
}

谢谢阅读。

转载于:https://www.cnblogs.com/Capella/p/9163362.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值