1. 程式人生 > 實用技巧 >檔案的管理與常用命令

檔案的管理與常用命令

void init() {
    for(int i = 1; i <= N; i++) f[i] = i;
}
 
int find(int k) {
    return f[k] == k? k : f[k] = find(f[k]);
}
 
void union(int a, int b) {
    f[find(b)] = find(a);
}

帶權並查集

假定a、b是兩個結點且a > b,a -> b表示區間[b, a)的和,b -> a表示負的區間[b, a)的和。需要將結點對轉化為一種左開右閉的形式以方便連線。
假設W1是要新增的邊,W4是實際新增的邊,它們之間的關係如下圖所示。

對於路徑壓縮,直接累加各邊權即可。

例題:HDU3038

http://acm.hdu.edu.cn/showproblem.php?pid=3038

//樣例輸入
5
10 100
10 28
3 32
6 41
6 1
 
//樣例輸出
1

將這個求解過程視覺化。

#include<bits/stdc++.h>
using namespace std;
 
int f[200010], w[200010];
 
int find(int k) {
    if(k != f[k]) {
        int a = find(f[k]);
        w[k] += w[f[k]];
        f[k] = a;
    }
    return f[k];
}
 
int N, M, A, B, S;
int main() {
    while(~scanf("%d%d", &N, &M)) {
        for(int i = 1; i <= N + 1; i++) {
            f[i] = i;
            w[i] = 0;
        }
        int ans = 0;
        while(M--) {
            scanf("%d%d%d", &A, &B, &S);
            B++;
            int Aa = find(A), Ba = find(B);
            if(Aa != Ba) {
                f[Ba] = Aa;
                w[Ba] = S + w[A] - w[B];
            }
            else if(w[B] - w[A] != S) ans++;
        }
        cout << ans << endl;
    }
}