带权并查集-How Many Answers Are Wrong

TT和FF是…朋友。嗯。。。非常好的朋友              

FF是个坏孩子,他总是向TT求爱,想跟他玩下一个游戏。这是一个非常无聊的游戏。首先,TT应该写下一个整数序列-!(无聊)              然后,FF可以从中选择连续的子序列(例如从第三个整数到第五个整数的子序列,包括在内)。之后,FF会问TT他选择的子序列的总和是多少。接下来,TT将回答FF的问题。然后,FF可以重做这个过程。最后,FF必须计算出整数的整个序列。              无聊~~无聊~~一个非常无聊的游戏!!!!TT根本不想和FF一起玩。为了惩罚FF,她经常故意告诉FF错误的答案。              坏孩子不是傻子。FF检测到某些答案不兼容。当然,这些矛盾使得计算序列变得困难。              但是,她是一个可爱的女孩。她没有勇气对FF很苛刻。为了节省时间,她保证如果没有逻辑错误,答案是正确的。              而且,如果FF发现一个答案是错误的,他在判断下一个答案时会忽略它。              但是会有太多的问题让可怜的FF无法确定当前的答案是对还是错。所以他决定写一个程序来帮助他解决这个问题。课程将收到FF的一系列问题以及FF从TT收到的答案。这个项目的目的是找出有多少答案是错误的。只有忽略错误的答案,FF才能算出整数的整个序列。可怜的FF没有时间做这项工作。现在他在寻求你的帮助~(为什么自找麻烦~~坏孩子

   输入              

第1行:两个整数,n和m(1<=n<=200000,1<=m<=40000)。意思是tt写了n个整数,ff问了她m个问题。            

 第2.m+1行:第i+1行包含三个整数:ai、bi和si。意思是tt回答ff,从ai到bi的总和是si。保证0<ai<=bi<=n。              

您可以假设任何子序列和都适合32位整数。            

   输出   

有多少答案是错误的。 

Sample Input

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

Sample Output

1

看得一头雾水,之前做过带权并查集的题,但是没有想到这种线段长度也是带权并查集,看了百度题解才明白,就是将线段ab变为两个数,c变为这俩个数的差值,首先要明确的一点是,线段的长度和数之间差值有什么区别,比如1-3的长度是20,那我们能说3比1大20吗?

自然是不能,这里要用数字的话,应该是3比0大20,所以这里要将数字的值变化一下,我们可以将a-1,将0当做根节点,也可以将b+1,将最大的数+1当做根节点。

之后的步骤,和带权并查集一样,在每次路径压缩和合并时更新关系,但是不同的是,这里的指向一定要明确,规定了值是大的指向小的,合并的时候都要将大的数合并到小的数上,至于关系如何更新,不懂自行百度,或者看下这篇博客:https://blog.csdn.net/qq_43644454/article/details/86542875

附上代码

#include<stdio.h>
#include<string.h>
struct ppp
{
    int dad,re;
} k[200010];
int ans;
int find(int x)
{
    int temp=k[x].dad;
    if(k[x].dad!=x)
    {
        k[x].dad=find(k[x].dad);
        k[x].re+=k[temp].re;
    }
    return k[x].dad;
}
int join(int a,int b,int c)
{
    int x,y;
    x=find(a);
    y=find(b);
    if(x>y)    //指向问题
    {
        k[y].dad=x;
        k[y].re=k[a].re-k[b].re-c;
    }
    else
    {
        if(x==y&&(k[a].re-k[b].re!=c))
            ans++;
        else
        {
            k[x].dad=y;
            k[x].re=k[b].re+c-k[a].re;
        }
    }
}
int main()
{
    int n,m,a,b,c;
    while(~scanf("%d %d",&n,&m))
    {
        for(int i=1; i<=200001; i++)
        {
            k[i].dad=i;
            k[i].re=0;
        }
        ans=0;
        for(int i=0; i<m; i++)
        {
            scanf("%d %d %d",&a,&b,&c);
            b++;           //这里我是将b+1.用最大值+1当作根节点
            join(a,b,c);
        }
        printf("%d\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43644454/article/details/86548775