hdu3038帶權並查集
阿新 • • 發佈:2021-09-24
鬱悶得很,送出了好幾發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(inta,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; } }