1. 程式人生 > 其它 >hdu3038帶權並查集

hdu3038帶權並查集

鬱悶得很,送出了好幾發wa,找不到錯在哪

學到:並查集的應用

這道題出現矛盾當且僅當讀入的區間的兩個端點均已出現過,且這兩個端點有一個共同的端點。

當兩個區間父親相同時我們嘗試計算。

當不同時我們可以合併。

合併的原理是,類似於把其中一個端點作為參照,val就是這個並查集中的點到這個參照點的差。

又因為差值和點是一一對應的,所以也不必擔心什麼加了後會出現負數啦,負數就是在它左邊。

然後在合併的時候只合並f1的val是因為這個並查集如果下次有再用到的話,在find函式裡會更新,沒有那就沒有這種需求了。

以及,為什麼是l--?

看了很多部落格,有的說這樣才可以合併【1,5】【6,10】區間,有的說端點會重複計算

我的理解是:

假設我們已經知道1-100以及1-60,那麼61-100我們就能計算了

此時題目給出61-100

把61變成60,60,100,就都在同一個並查集裡,並且算出來結果是對的。

如果不加的話,61就不在並查集裡了。

#include <iostream>
#include <math.h>
#include <string.h>
#include <vector>
#include <map>
#include <queue>
#include <stdio.h>
#include <algorithm>
#include 
<cstdio> using namespace std; int ans,n,m,val[500000],fa[500000]; int find(int x) { if(fa[x]!=x) { fa[x]=find(fa[x]); val[x]+=val[fa[x]]; } return fa[x]; } void pre( ) { ans=0; for(int i=0;i<=n;i++) { fa[i]=i; val[i]=0; } } void unit(int
a,int b,int value) { int f1=find(a),f2=find(b); if(f1==f2)//同一個父親可以判斷區間長度了 { if(abs(val[b]-val[a])!=value) { ans++; } } else { fa[f2]=f1; val[f2]=val[a]+value-val[b]; } } int main() { //freopen("9241.in","r",stdin); while(~scanf("%d%d",&n,&m)) { pre( ); for(int i=1;i<=m;i++) { int l,r,e; scanf("%d%d%d",&l,&r,&e); l--; unit(l,r,e); } cout<<ans<<endl; } }