HDU 3038 How Many Answers Are Wrong 帶權並查集 向量

解題報告:

思路:對於每次給出的兩個端點進行並查集合並,查找兩個端點父親節點相等,比較。不相等,合併。比較:此時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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章