HUD 3038 带权并查集 解决区间和矛盾问题

How Many Answers Are Wrong

TT and FF are ... friends. Uh... very very good friends -________-b 

FF is a bad boy, he is always wooing TT to play the following game with him. This is a very humdrum game. To begin with, TT should write down a sequence of integers-_-!!(bored). 


Then, FF can choose a continuous subsequence from it(for example the subsequence from the third to the fifth integer inclusively). After that, FF will ask TT what the sum of the subsequence he chose is. The next, TT will answer FF's question. Then, FF can redo this process. In the end, FF must work out the entire sequence of integers. 

Boring~~Boring~~a very very boring game!!! TT doesn't want to play with FF at all. To punish FF, she often tells FF the wrong answers on purpose. 

The bad boy is not a fool man. FF detects some answers are incompatible. Of course, these contradictions make it difficult to calculate the sequence. 

However, TT is a nice and lovely girl. She doesn't have the heart to be hard on FF. To save time, she guarantees that the answers are all right if there is no logical mistakes indeed. 

What's more, if FF finds an answer to be wrong, he will ignore it when judging next answers. 

But there will be so many questions that poor FF can't make sure whether the current answer is right or wrong in a moment. So he decides to write a program to help him with this matter. The program will receive a series of questions from FF together with the answers FF has received from TT. The aim of this program is to find how many answers are wrong. Only by ignoring the wrong answers can FF work out the entire sequence of integers. Poor FF has no time to do this job. And now he is asking for your help~(Why asking trouble for himself~~Bad boy) 

Input

Line 1: Two integers, N and M (1 <= N <= 200000, 1 <= M <= 40000). Means TT wrote N integers and FF asked her M questions. 

Line 2..M+1: Line i+1 contains three integer: Ai, Bi and Si. Means TT answered FF that the sum from Ai to Bi is Si. It's guaranteed that 0 < Ai <= Bi <= N. 

You can assume that any sum of subsequence is fit in 32-bit integer. 

Output

A single line with a integer denotes how many answers are wrong.

Sample Input

10 5
1 10 100
7 10 28
1 3 32
4 6 41
6 6 1

Sample Output

1

题意:求在有n个数中,有m次询问,每次询问在这给定的区间和这区间里数的和为s,求每次给出的是不是正确的和s。也就是和前面的矛盾不矛盾。

 

分析:要求这些话中是否存在矛盾的问题,很明显的并查集(在这里要说一下并查集是什么:并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。);首先知道并查集是将具有同一种属性的元素放在同一棵树中,然后这一棵树通过路径压缩的方式使其子节点都具有同一个根节点,即指向同一个根节点

但是!!如果如果只是将两个点进行合并的话肯定是不符合题意,因为这两点还有一定的关系信息;这就是带权并查集的特点

处理带权并查集的最重要的思想就是用到向量的关系来处理;PS一位神犇blog:https://blog.csdn.net/niushuai666/article/details/6981689

处理的核心思想已经有了,剩下的就是处理相对关系了,也就是细节,先上代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int N=1e6+7;
int m,n;
int f[N];
int ran[N];//ran[i]代表i节点到父结点的关系,其实通过f的路径压缩就变成到根节点的关系了
int ans=0;
int Findf(int v){
    if(f[v]==v) return v;
    int t=f[v];
    f[v]=Findf(f[v]);
    ran[v]+=ran[t];//……1
    return f[v];
}
void Union(int a,int b,int w){
    int t1=Findf(a);//建立树的时候将a作为根
    int t2=Findf(b);
    if(t1==t2){//w是b-->a的关系
        if(ran[a]+w!=ran[b])//也是由向量的三角形法则得到的相对关系……2
            ans++;
    }else{

        f[t2]=t1;
        ran[t2]=w+ran[a]-ran[b];//……3
    }
    return;
}
void Init(){
    memset(ran,0,sizeof ran);
    rep(i,0,n+1) f[i]=i;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    while(scanf("%d%d",&n,&m)!=EOF){//不多组输入就会WA
    ans=0;
    Init();
    rep(i,1,m){int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        Union(u,v+1,w);//这一点就是一定是u-1,v;或者是u,v+1,这样才能做到两者相连接
    }                  //比如,连接区间1--2,3--4,这样就能将区间1--4连接起来;
    printf("%d\n",ans);
    }
 return 0;
}

在这里我解释一下我代码标注1 2 3的三行

第一处,也就是标1的那一行(下面就用数字代替行了):为什么是"+";首先要明确,ran数组存放的是下标i到其父节点的关系,那么既然是关系,由大神的向量的思想就可以知道了为什么是加,有图有真相:

假设f[a]=b(f数组是存放其父节点是谁),由并查集的路径压缩的思想,f[a]最终是指向root的,也就是f[a]=root,既然是这样,那就必须要改变ran[a]的值了,不改变之前ran[a]是存放a到b点的关系,改变之后那就需要存放a到root节点的关系,由向量的三角形的法则,a-->root的关系就是a-->b的关系+b-->root的关系,这就是为什么相加的原因;

第二处:要知道如果到达当前语句是说明了,a b两个点的根节点是否相同(其实上面的if语句可以改为if(f[a]==f[b]),也是可以),既然相同那就需要比较了

比如先说了连个区间

1-10 10

1-5 2

6-10 5

跟明显第三句话就可以看出来问题了,第二个加第三个跟第一个不相等,但是他们表述的区间都是相同的,所以产生矛盾,不过这种矛盾应该怎么判断呢,我们可以以它的端点为点建立一个集合,他们的根就是能到达的最左端,如果都有相同的最左端那么就可以判断一下是否有矛盾产生。


比如上面这个图, 我们已经知道了AB的长度和AC的长度,如果下面再来一个CB,我们就可以知道C的最左端是A,B的最左端也是A,那么就可以判断一个AC+CB的长度是不是等于AB的长度就可以了。。。。
借用原文:https://blog.csdn.net/yu121380/article/details/80453611 

其实本质上还是向量相加原则

第三处:在处理压缩并查集的时候子节点虽然在函数递归的过程中相会连接,但是如果说两者存在关心那就需要将两者的根节点相连,在这里我采用的是将其“靠左原则”,什么意思?

就是看上面的Union函数传参a不是在b的左边吗,如果将其两者的的根节点合并,那么就是f[rootb]=roota,这就是b的根节点就是a的根节点的孩子了;当然你也可以换过来;

同样的ran的关系数组也要做同样的处理,这里的处理还是靠左原则,

(这个图和我的靠左原则正好反了,这是靠右,注意一下将roota-->rootb改为rootb-->roota,a-->b改为b-->a,最好自己再重新画一下)借用这张图就能说明是怎么相加的:

我要将roota连接到rootb上,就是ran[roota]等于什么;

我们呢现在有a-->b的关系w,b-->rootb的关系ran[b],a-->roota的关系ran[a],由向量的加法就能得到rootb-->roota=ran[a]+w-ran[b];

 

PS:poj1182也是带权并查集,其处理的细节有点不同,需要推出他们的关系来

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值