加權並查集詳解
阿新 • • 發佈:2019-01-24
加權並查集,就是普通的並查集加了個權值。以題目來舉例吧。
題意:給你m個區間的區間端點及區間和,一個個的讀入這些區間,問有多少個區間與前面的區間衝突。
分析:將區間端點看成是一個節點,用一個parent[i]陣列表示結點i指向的父節點,用一個sum[i]陣列表示結點i到父節點的權值。運用了字首和的思想。
程式碼:
#include<iostream> #include<cstring> using namespace std; const int N = 2e5+5; int n,m,s[N],p[N],ans; void init(){ ans=0; memset(s,0,sizeof(s)); for(int i=0;i<N;i++) p[i]=i; } int fd(int x) { ///此時find不單有查詢任務,還有更新距離任務 if(x==p[x]) return x; int t=p[x]; p[x]=fd(p[x]); s[x]+=s[t]; ///記錄到根節點的距離,一定要有一個思想,根節點是一個區間的一個端點而不是一個區間,輸入的區間被合併成了兩個點 return p[x]; } void Union(int a,int b,int num) { int x=fd(a),y=fd(b); if(x==y) { if(s[b]!=s[a]+num) ans++; }else { p[y]=x; s[y]=s[a]+num-s[b]; ///y到x的距離等於a到x的距離+b到a的距離-b到y的距離 } } int main(){ while(cin>>n>>m) { init(); for(int i=0;i<m;i++) { int a,b,c; cin>>a>>b>>c; Union(a-1,b,c); ///等價於Union(a,b+1,c); } cout<<ans<<endl; } }
牛客網 第十四屆華中科技大學程式設計競賽決賽同步賽 A - Beauty of Trees 點選開啟連結
題意:給你m個區間的區間端點及區間亦或和,一個個的讀入這些區間,問有多少個區間與前面的區間衝突。
分析:此題與上一題差不多,只不過將區間和改成了區間亦或和,原理都是一樣的,利用亦或的性質維護一個字首亦或和。
程式碼:
#include<iostream> #include<cstring> using namespace std; const int N = 1e5+10; int n,m,s[N],p[N],k,f; void init(){ f=0; for(int i=0;i<N;i++) p[i]=i; memset(s,0,sizeof(s)); } int fd(int x) { if(x==p[x]) return x; int t=p[x]; p[x]=fd(p[x]); s[x]^=s[t]; return p[x]; } void Union(int a,int b,int c) { int x=fd(a),y=fd(b); if(x==y) { if(s[b]!=(s[a]^c)) cout<<k<<endl,f=1; ///亦或這裡一定要打括號,亦或的優先順序低於!= }else { p[y]=x; s[y]=s[a]^s[b]^c; } } int main(){ while(cin>>n>>m) { init(); for(k=1;k<=m;k++) { int a,b,c; cin>>a>>b>>c; Union(a-1,b,c); } if(!f) cout<<-1<<endl; } }