题目链接:https://vjudge.net/contest/168086#problem/D
题目大意:: n表示有一个长度为n的数组, 接下来有m行形如x, y, d的输入, 表示从第x,个元素到第y个元素的和为d(包括x, 和y), 问m行输入里面有几个是错误的(第一个输入是正确的);
思路参考:https://www.cnblogs.com/geloutingyu/p/6132190.html
这题你不告诉我是并查集,我怎么想得到。。。
复习一下带权并查集吧。用dis数组维护一个点到他当前父亲节点的距离,那么在find_set时就可以动态地更新这个值,这就叫做路径压缩。
这题思路如下,一切尽在不言中
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
const int maxn=200000+10;
int fa[maxn];
int dis[maxn];//维护每个点到其父节点的距离
int find_set(int x){
if(fa[x]!=x){
int root=find_set(fa[x]);
dis[x]+=dis[fa[x]];
return fa[x]=root;
}
else{
return x;
}
}
int Union(int x,int y,int d){
int fx=find_set(x);
int fy=find_set(y);
if(fx==fy){
if(abs(dis[x]-dis[y])!=d){
return 0;
}
}
else{
if(fx<fy){
fa[fx]=fy;
dis[fx]=dis[y]+d-dis[x];//路径压缩
}
else{
fa[fy]=fx;
dis[fy]=dis[x]-dis[y]-d;
}
}
return 1;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=0;i<=n;i++){
fa[i]=i;
}
memset(dis,0,sizeof(dis));
int ans=0;
for(int i=1;i<=m;i++){
int x,y,d;
scanf("%d%d%d",&x,&y,&d);
if(!Union(x-1,y,d)){
ans++;
}
}
printf("%d\n",ans);
}
return 0;
}