解題報告:
思路:對於每次給出的兩個端點進行並查集合並,查找兩個端點父親節點相等,比較。不相等,合併。比較:此時ra = rb,我用rt表示,a -> b = a ->rt - b->rt,將運算結果和d比較就行了。對於合併:可以列出兩個向量表達式:a->b + b->ra = a ->ra
b->ra + ra->rb = b->rb,求出ra->rb = a->b + b->rb - a->ra。這個時候定義dis數組含義:代表該節點到根節點的相對距離。
最後還有一個要注意的點,就是a要減1,可以這樣的理解:
x a b
x爲根節點,看這個數軸就知道爲什麼要減1了。
代碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+10;
ll rt[N], dis[N];
ll n, m;
ll ans;
void init(){
for(ll i=0; i<=n; ++i){
rt[i] = i;
dis[i] = 0;
}
}
ll Find(ll x){
if(x != rt[x]){
ll root = rt[x];
rt[x] = Find(rt[x]);
dis[x] += dis[root];
}
return rt[x];
}
void Union(ll x, ll y, ll d){
ll rtx = Find(x);
ll rty = Find(y);
if(rtx == rty){
if(dis[x] - dis[y] != d)++ans;
}else {
rt[rtx] = rty;
dis[rtx] = d + dis[y] - dis[x];
}
}
void solve(){
ans = 0;
for(ll i=0; i<m; ++i){
ll x, y, d;
scanf("%lld%lld%lld", &x, &y, &d);
--x;
Union(x, y, d);
}
printf("%lld\n", ans);
}
int main(){
while(~scanf("%lld%lld", &n, &m)){
init();
solve();
}
return 0;
}