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);
}
}