P1196(洛谷)银河英雄传说(详细解答)

题目:
银河英雄传说

题意解释:
起始有3w艘战舰,每条战舰独自成一列,共3w列,输入Mij指令将第i号战舰所在的整列放到j号战舰后,Cij查询i号战舰和j号战舰中间有多少战舰,若ij不在同一列返回-1。(每个战舰看成一个结点)

解题思路:

fa[]数组存放每个点的父亲节点
value[]数组存放该点到头结点之间共有多少结点(不包括该点)
tot[]数组存放整列共有多少结点,放在头结点位置

使用带权并查集,边权存该结点到头结点(包括头结点,但不包括该点),一共有多少结点,同时头结点存放整列共有多少结点。路径压缩时直接按照带权并查集的处理方式即可,合并集合时除了带权并查集的合并之外,还要更新头结点的tot数。

代码:

#include<bits/stdc++.h>
#define maxn 30010
using namespace std;
int fa[30010],value[30010],tot[30010];//tot用于存放这一列一共有多少节点,放在头结点
//并查集核心系操作,寻找父亲节点
int findFa(int x)
{
    if(x==fa[x])return x;//只有父亲节点才为本身
    int new_fa=findFa(fa[x]);//new_fa存放找到的父亲节点
    value[x]+=value[fa[x]];//x的权值加上父亲的权值
    fa[x]=new_fa;
    return new_fa; //返回new_fa
}


int main()
{
    for(int i=1; i<=30000; i++)
    {
        fa[i]=i,value[i]=0,tot[i]=1;//初始时每一个节点都是头结点
    }
    int T,x,y;
    char ch;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s%d%d",&ch,&x,&y);
        if(ch=='M')//M进行合并
        {
            value[findFa(x)]+=tot[findFa(y)];//更新x的父亲节点fa[x]的权值
            tot[fa[y]]+=tot[fa[x]];//更新y的父亲节点fa[y]的tot值
            fa[fa[x]]=fa[y];//将x的父亲节点fa[x],指向y的父亲节点fa[y]
        }
        else  //C进行查询
        {
            if(findFa(x)==findFa(y))//x和y在同一列
            {
                cout<<abs(value[x]-value[y])-1<<endl;
            }
            else  //不在同一列
            {
                cout<<-1<<endl;
            }
        }
    }
    return 0;
}

代码图解:
findFa()方法图解每次找父亲结点,并且路径压缩后的结果:
在这里插入图片描述
大家注意第一次value[A]=1而不是2,这是因为我将B连接到C只是更新的B的value
还没有更新valueA,只有等下一次执行findFa()的时候我在压缩路径,将valueA变为2。大家可以拿笔找着代码执行以下就知道了!

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值