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

题目来源:https://vjudge.net/problem/HDU-3038
【题意】
给出n,m,下面m行每一行有三个数,a,b,v,v代表的是区间【a,b】的和,每一行都是这样,但是当第i行与前i-1行发生冲突的时候,记录一下。输出共错误多少句。举个例子:第一行是 1 100 200,第二行是1 50 300,这就发生了冲突。
【思路】
http://blog.csdn.net/dextrad_ihacker/article/details/51016017
这个大佬的博客写的很清晰(有配图),很容易理解。以下是我的个人见解(当然,也只是对大佬的话语的重复)。
首先,要理解第i行,a,b,v,假设用dis代表距离,那么dis(a-b)=v;但是前i-1行不一定有一模一样的a,b,v,所以就要借助一个过渡,假设是c,那么就可以这样:dis(a-c)-dis(b-c)=v,有没有发现如果我们把他们共同的根节点也就是祖先,当做c的话,只需要知道节点a到祖先的距离,节点b到祖先的距离,就可以知道a和b的距离了(假设他们有共同的祖先),那如果a和b没有共同的祖先,那么在之前就找不到他们俩的关系,就不能确定dis(a-b)=v这个关系为假。就可以把他们的父节点连在一起,即把他俩各自的祖先弄到一起,比如把a的祖先拿去给b的祖先当父亲。
还有一点,给出的是一个闭区间,【a,b】,但是他可以转化为(a-1,b],左开右闭。半闭半开区间有一个性质,就是 (a,b]+(b,c]=(a,c];
还有一点灰常重要的东西是怎么求a,b之间的距离。
假如一开始没关系,那么用rank数组来表示a,b各自到各自祖先的距离。那么在把a的祖先给b的祖先当父亲之后,那么b到祖先的距离也就是rank【b】就要再加上b原本的祖先到a的祖先的距离,更新一下,其中find函数(找根节点的函数)里rank【x】+=rank【pre【x】】(这里pre数组存的是对应数的父节点)。
【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<set>
using namespace std;
typedef long long LL;
int pre[200010],ranks[200010];
int find(int root)
{
    if(pre[root]==root)return root;
    int t=find(pre[root]);
    ranks[root]+=ranks[pre[root]];//精髓
    return pre[root]=t;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        int ans=0;
        for(int i=1; i<=n; i++)
            pre[i]=i;//把各自的父节点赋给他本身
        memset(ranks,0,sizeof(ranks));
        while(m--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            a--;
            int fa=find(a);
            int fb=find(b);
            if(fa!=fb)
            {
                pre[fb]=fa;
                ranks[fb]=ranks[a]-ranks[b]+c;//更新距离
            }
            else
            {
                if(ranks[b]-ranks[a]!=c)
                    ans++;
            }
        }
        printf("%d\n",ans);
    }

}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值