檔案的管理與常用命令
阿新 • • 發佈:2020-09-20
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; } }