题意:
给出一些区间和的值,询问最少会有多少个值是错的,如果不能确定是对是错的就算是对的。
思路:
用带权并查集来做,输入u,v,w代表区间u到v的区间和为w。用并查集来检查u,v是否在同一个集合,如果在同一集合,说明我们之前已经有了u,v之间的关系,而现在输入的u,v,w就用来检查之前的关系是否和现在输入的一致,如果不一致,肯定就错了。如果不在同一集合,那么就可以更新关系了。带权并查集中的权值存的是该数字和它的前置结点的差值,并在不断递归找根节点时将权值相加就能够得到该数字和根节点之间的差值了。如权值val[v]等于v的值减去pre[v]的值,不断递归相加时就得到了v与其根节点f2的权值。
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#define LL long long
#define MAX 1000005
#define inf 99999999999
#define mod 1000000007
using namespace std;
int pre[2000005],val[2000005];
int Find(int x)
{
if(x!=pre[x])
{
int t=pre[x];
pre[x]=Find(pre[x]);//递归找根节点
val[x]+=val[t];//递归相加权值,得到开始的x与其根节点的相对关系
}
return pre[x];
}
int main()
{
int m,n,i,ans,u,v,w,f1,f2;
while(scanf("%d %d",&m,&n)!=EOF)
{
for(i=0;i<=m;i++)
{
pre[i]=i;
val[i]=0;
}
ans=0;
for(i=1;i<=n;i++)
{
scanf("%d %d %d",&u,&v,&w);
u=u-1;//前置一位
f1=Find(u);
f2=Find(v);
if(f1!=f2)
{
pre[f2]=f1;
val[f2]=val[u]-val[v]+w;//将u的根节点f2连接到f1上,得出val[f2],下次再循环递归时便可将u和v根节点都当成f1来计算。
}
else
{
if(val[v]-val[u]!=w)//检查之前关系于现在是否冲突
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}