HDU - 3038How Many Answers Are Wrong (扩展并查集。)

题意:

给出区间[1,n],下面有m组数据,l r v区间[l,r]之和为v,每输入一组数据,判断此组条件是否与前面冲突 ,最后输出与前面冲突的数据的个数.

用到了向量偏移的方法。

a 的父亲是 roota,,b 的父亲是 rootb ,对于a,b 两个集合我们怎么把他们合并呢?

假设让 roota -> rootb, 我们用dis[a] 表示 a 到根节点的距离。

roota -> rootb = b -> rootb - b -> roota.

a -> roota = a -> b + b -> roota,

因此,, roota -> rootb = b -> rootb - a -> roota + a -> b

即  roota -> rootb = dis[b] - dis[a] + S ; // 此时的 dis[a] 是指到 roota 的距离。

如果 a b 在有同一个祖先,那么我们就查一下,,dis[a] - dis[b] 的绝对值是不是 和 给定的 S 相同。

不同就是假的话,

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(x,v) memset(x,v,sizeof(x)) 
#define go(i,a,b)  for (int i = a; i <= b; i++)
#define og(i,a,b)  for (int i = a; i >= b; i--)
using namespace std;
typedef long long LL;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
const int N = 200000 + 10;

int n,m;
int f[N],dis[N];
int find(int k){
	if (f[k] == k) return k ;
	int temp = f[k];
	f[k] = find(f[k]);
	dis[k] += dis[temp];
	return f[k];
}
int main(){
	while(~scanf("%d%d",&n,&m)){
		go(i ,0 ,n) f[i] = i,dis[i] = 0;
		int ans = 0;
		go(i,1,m){
			int x,y,z,xx,yy;
			scanf("%d%d%d",&x, &y,&z);x--;
			xx = find(x); yy = find(y);
			if (xx != yy){
				f[yy] = xx;
				dis[yy] = dis[x] + z - dis[y];
			} else {
				if (abs(dis[x] - dis[y]) != z) ans ++;
			}

		}
		printf("%d\n",ans);
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/kidsummer/article/details/81665848