题意:
给出区间[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;
}