题目链接:https://vjudge.net/problem/HDU-3038#author=jack10086
转自:https://blog.csdn.net/weixin_44224825/article/details/104241108
题意:给多个区间以及区间和,假设前面的推论是正确的,求有多少矛盾的推论。区间和不能为负数。例如1-10=100,1-5=200就是矛盾的。
思路:pa[i]表示和i有关系的最左端的点,设为根节点,dis[i]表示i距离pa[i]的距离。每次输入区间a,b时,如果两个数的根节点x,y相同,说明是有相同的参照数,因此可以计算两点间的距离。如果不相同,说明没有相同的标准,因此不能计算,但是有了d,a与b所在的集合可以建立关系。合并两个数所在的集合,注意x和y的大小关系。
这里的a–是为了特判6 6 1此类的数据的情况。 一般区间类题目都会这样操作。
并查集修改距离时,应该先按照距离根节点位置从小到大修改,也就是说dis的修改不能在pa修改之前。例如1<-2<-3<-4,在一开始,pa[3]=2,pa[4]=3,此时dis[3]记录的是2与3间的距离,如果先修改dis[4],就会出错。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
const int maxn=2e5+5;
int pa[maxn],dis[maxn];
int fnd(int x)
{
if(pa[x]==x)
return x;
int pre=pa[x];
pa[x]=fnd(pa[x]);
dis[x]+=dis[pre];
return pa[x];
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
memset(dis,0,sizeof(dis));
for(int i=1; i<=n; i++)
{
pa[i]=i;
}
int a,b,d;
int ans=0;
for(int i=0; i<m; i++)
{
scanf("%d%d%d",&a,&b,&d);
a--;
int x=fnd(a),y=fnd(b);
if(x!=y)
{
if(y>x)
{
pa[y]=x;
dis[y]=dis[a]+d-dis[b];
}
else
{
pa[x]=y;
dis[x]=dis[b]-dis[a]-d;
}
}
else
{
if(dis[a]+d!=dis[b])
{
ans++;
}
}
}
printf("%d\n",ans);
}
return 0;
}