http://acm.hdu.edu.cn/showproblem.php?pid=3038
问题概述:输入一个数n表示一个数组有n个数,再输入一个m表示m个信息,其中每个信息(a,b,c)表示区间[a,b]中所
数的和为c,如果某个信息与前面的信息冲突,那么这个信息就是错的并且无效,求错误信息个数(HDU3038)
输入样例: 对应输出:
10 5 1
1 10 100
7 10 28
1 3 32
4 6 41
6 6 1
带权并查集:和并查集很相似,只不过多了一个dis[]数组来记录每个点到它祖先的距离
→距离压缩:x到新祖先的距离==x到旧祖先的距离+旧祖先到新祖先的距离,既dis[x] = dis[x]+dis[f[x]]
→信息审查:每次读入一个范围,判断这个范围是否在一个集合中,若在就立刻判断它们的距离差即dis[r]-
dis[l]==x?如果不在一个集合中,合并
#include<stdio.h>
#include<string.h>
int ufs[200005], dis[200005];
int Find(int x)
{
int temp;
if(ufs[x]==-1)
return x;
temp = Find(ufs[x]); /*这个一定要放在前面,否则可能无法保证dis[x]为它到当前祖先的距离*/
dis[x] += dis[ufs[x]];
return ufs[x] = temp;
}
int main(void)
{
int n, m, l, r, w, i, t1, t2, ans;
while(scanf("%d%d", &n, &m)!=EOF)
{
memset(ufs, -1, sizeof(ufs));
memset(dis, 0, sizeof(dis)); /*初始化dis数组为0,因为此时每个点的祖先都是它自己*/
ans = 0;
for(i=1;i<=m;i++)
{
scanf("%d%d%d", &l, &r, &w);
l--;
t1 = Find(l);
t2 = Find(r);
if(t1!=t2)
{
ufs[t2] = t1;
dis[t2] = dis[l]-dis[r]+w; /*dis[t2]+dis[r]-w=dis[l]*/
}
else
{
if(dis[r]-dis[l]!=w)
ans++;
}
}
printf("%d\n", ans);
}
return 0;
}