How Many Answers Are Wrong(带权并查集)

题目

题目解释:

给定n个数,m个数据对,数据对中有abc a代表起始数字,b代表终止数字,c代表权值,可以理解为a到b的距离我们要在给出的m个数据对中,找出自相矛盾的数据对,统计一共有多少对错误。

举例说明
为了方便后边,我们把右边的闭区间改为开[a,b+1)
n=10,m=5(数字1~10,5个数据对)
1 10 100
7 10 28
1 3 32
4 6 41
6 6 1
[1,11)距离为100
[7,11)距离为28
[1,4)距离为32
[4,7)距离为41
[6,7)距离为1

输出 1

解题思路:
对于这个题目,我们是不知道数列的具体内容,只知道若干区间上的距离是多少,然而如果区间是相邻的,那么他们可以组成一个更大的区间,也就是通过已有区间能推理出更多区间和。
这道题使用带权并查集的做法很好处理,每一个节点表示一个区间的起点,它的父亲节点表示这个左闭右开区间的右端点,边上的权值就存放起点到父亲节点的距离,对于给出每一组数据对,判断是否连通,如果是,就判断给出的数据和推得的数据是否吻合,如果不连通,就通过并查集的合并操作使其连通!

图示:
此图解释了4 6 41 的错误进行解释,大家好好理解!
在这里插入图片描述
findFa()进行解释:

int findFa(int x)
{
    if(x==fa[x])return x;
    int new_fa=findFa(fa[x]);//用new-fa暂存父亲节点
    value[x]+=value[fa[x]];//更新x的value值
    fa[x]=new_fa;//路径压缩
    return fa[x];
}

这个find方法和普通的并查集find方法唯一区别在于,要更新value值,并且要压缩路径!我用一个图片来解释,执行findFa()后的效果,至于执行细节、大家用一组数据写写画画即可!
在这里插入图片描述

代码:(有详细解释)

#include<bits/stdc++.h>
#define maxn 200010
using namespace std;
int fa[maxn],value[maxn];//fa存放父亲节点,value存放到父亲节点的距离
int n,m,ans;
int findFa(int x)
{
    if(x==fa[x])return x;
    int new_fa=findFa(fa[x]);//用new-fa暂存父亲节点
    value[x]+=value[fa[x]];//更新x的value值
    fa[x]=new_fa;//路径压缩
    return fa[x];
}

int main()
{
    while(cin>>n>>m)
    {
        //并查集初始化
        for(int i=1; i<=n; i++)
        {
            fa[i]=i,value[i]=0;//初始权值0
        }
        int a,b,s;
        for(int i=1; i<=m; i++)
        {
            cin>>a>>b>>s;
            if(findFa(a)==findFa(++b))//a和b+1有相同父亲节点
            {
                ans+=value[a]!=(value[b]+s);//如果相等返回0,不相等ans++
            }
            else
            {
                //不连通情况,进行Union合并
                value[fa[a]]=s+value[b]-value[a];//先更新a的父亲节点的权值
                fa[fa[a]]=fa[b];//将a的父亲节点,连接到b的父亲节点
            }
        }
        printf("%d",ans);
    }
    return 0;
}

对这段代码进行图解:

  value[fa[a]]=s+value[b]-value[a];//先更新a的父亲节点的权值
                fa[fa[a]]=fa[b];//将a的父亲节点,连接到b的父亲节点

这是a,b不连通情况,我们要变为连通。(a,b父亲为c,d并都用大写)
在这里插入图片描述

这道题就讲到这里了,作图不易,大家点个赞,粉丝太少了呜呜~~多多关注!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值