HDU3038 How Many Answers Are Wrong【帶權並查集】
阿新 • • 發佈:2018-12-14
題目描述:
給定一系列的區間和,可能有一部分與之前給定的衝突; 如:第一步給出 1-10的區間和為100, 第二步給出7-10的區間和為20,第三步給出1-5的區間和為90(顯然這是個與之前相沖突的語言,即錯誤!) 乍看起來挺難的,其實也挺難的(23333)。感覺是帶權並查集的基礎?反正就是得用到向量思維+帶權並查集可以過。
思路:
看這位巨巨的部落格:點選學習帶權並查集 需要用到向量思維 設定sum陣列為當前結點到父結點的和。例如6 10 100,則設定id[6] = 10, sum[6] = 100。代表6的父結點是10,而6到10的和為100。由於A[6] + A[7] + A[8] + A[9] + A[10] = sum[10] - sum[5],所以輸入後進行處理,這樣在後面的換算中可以直接得出相減得到答案。 同樣得,在帶權並查集中,使用向量思維去求即可。 【路徑壓縮】 由於sum陣列為當前結點到父結點的和,當將當前結點的父結點指向結點的爺爺結點,r的值需要從【當前結點到父結點的和】變成【當前結點到父結點的和 + 父結點到爺爺結點的和】.
易錯點:
1.輸入輸出有多組資料,題目並沒有給出; 2.在儲存區間和的時候,做端點-1 , 易於後續的計算(這裡還是手動模擬一下建樹容易理解);
程式碼:
#include <bits/stdc++.h>
using namespace std;
#define MAX 200010
int pre[MAX], sum[MAX];
void init(int n)
{
for(int i = 0; i<=n; i++)
{
pre[i] = i;
sum[i] = 0;
}
}
int Find(int x)
{
while (pre[x] != pre[pre[x]])
{
sum[x] = sum[x] + sum[pre[x]];
pre[x] = pre[pre[x]];
}
return pre[x];
}
void Union(int x, int y, int val)
{
int xRoot = Find(x);
int yRoot = Find(y);
if(xRoot != yRoot)
{
pre[xRoot] = yRoot;
sum[xRoot] = sum[y] - sum[ x] + val;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
while(cin >> n >> m)
{
int ans = 0;
init(n);
for(int i = 0; i<m; i++)
{
int x, y, val;
cin >> x >> y >> val;
x--;
if(Find(x) == Find(y))
{
if(sum[x] - sum[y] != val)
{
ans++;
}
}
else
{
Union(x, y, val);
}
}
cout << ans << endl;
}
return 0;
}