hdu3038(带权并查集)

题目链接: http://acm.split.hdu.edu.cn/showproblem.php?pid=3038

 

题意: n表示有一个长度为n的数组, 接下来有m行形如x, y, d的输入, 表示从第x,个元素到第y个元素的和为d(包括x, 和y), 问m行输入里面有几个是错误的(第一个输入是正确的);

 

思路: 很显然带权并查集咯,我们可以用距离的概念代替和的概念比较好理解一点,d表示x到y的和即x到y的距离;

可以用rank[x]表示x到其父亲节点的距离,  将正确的距离关系合并到并查集中(错误的当然不能合并到里面啦);

要注意的是这里的x, y是闭区间, 我们不好直接处理, 要先将其变成开区间来, [x, y]等价于(x-1, y]或者[x, y+1);

还有要注意有多组输入(坑爹)......

 

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #define MAXN 200010
 4 using namespace std;
 5 
 6 int pre[MAXN], ran[MAXN];
 7 
 8 int find(int x){
 9     if(x!=pre[x]){
10         int fx=find(pre[x]);
11         ran[x]=ran[x]+ran[pre[x]]; //***路径压缩过程中更新rank的值, 至于这个更新的公式嘛画线段图很容易看出来的啦
12         pre[x]=fx;
13     }
14     return pre[x];
15 }
16 
17 int jion(int x, int y, int d){
18     int fx=find(x);
19     int fy=find(y);
20     if(fx==fy){ // **路径压缩后fx,fy即为x, y的父亲节点, 如果他们父亲节点相同的话我们就可以判断是否与并查集里面的关系矛盾,这个我们也可以画线段图看出来啦
21         if(ran[x]-ran[y]!=d){
22             return 1;
23         }
24     }else{ //***合并后更新rank值, 和前面一样画线段图就OK了啦
25         if(fx<fy){
26             pre[fx]=fy;
27             ran[fx]=ran[y]+d-ran[x];
28         }else{
29             pre[fy]=fx;
30             ran[fy]=ran[x]-ran[y]-d;
31         }
32     }
33     return 0;
34 }
35 
36 int main(void){
37     int n, m, d, x, y, ans=0;
38    while(~ scanf("%d%d", &n, &m)){
39     ans=0;
40     for(int i=0; i<=n; i++){
41         pre[i]=i;
42         ran[i]=0;
43     }
44     while(m--){
45         scanf("%d%d%d", &x, &y, &d);
46         if(jion(x, y+1, d)){ //注意题目给出的是闭区间, 我们将其化成半开区间来比较好处理
47             ans++;
48         }
49     }
50     printf("%d\n", ans);
51     }
52     return 0;
53 }

 

转载于:https://www.cnblogs.com/geloutingyu/p/6132190.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值