筆者最近刷到了一道帶權並查集的題目,當做入門博客寫一篇學習筆記吧。
題目中要求求距離+換爹,很顯然,暴力的dfs在20000的數據下絕對會被卡的。
自然想到,什么數據結構可以快速維護父子關系?
顯然有並查集。
那么,我們要做的就是修改並查集,使它能夠維護距離了。
那么,我們在每一次更新父親(路徑壓縮)的時候更新距離。
先來看最基本的find函數:
inline int find(int x){ return x==f[x]?x:f[x]=find(f[x]); }
我們要在這時候維護距離dis的改變。
於是,我們先記錄下路徑壓縮前的父親。
然后壓縮。
返回的時候,當前的結點要累加之前的距離即可。
代碼:
inline int find(int x){ if(x==f[x])return x; int t=f[x];//記錄之前父親 f[x]=find(f[x]);//並查集find dis[x]+=dis[t];//累加距離 return f[x]; }
對於多組訓我,切記清空數組。並查集的初始化不要忘記。
將dis數組初始化為0,f數組照常賦值成自己。
對於第一個操作,直接認爹,然后更新距離。
所以,對於第二個E操作,在詢問的時候要find一下,以便於更新之前沒有更新的距離。之后直接輸出即可。
注意,dis[x]維護的是x到根的距離。
並查集是樹形結構。
總代碼:
#include<cstdio>//加權並查集 #include<iostream> #include<cstring> using namespace std; int dis[50000],f[50000]; int n,x,y,t; char s[50]; /*st struct node{ int next,to; }; head[5000]; inline void add(int x,int y){ e[++tot].to=y; e[tot].next=head[x]; head[x]=tot; }*/ inline int abs(int x){return x<0?-x:x;} inline void read(int &x){ int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }while(ch>='0'&&ch<='9'){ s=(s<<1)+(s<<3)+(ch^48); ch=getchar(); }x=s*w; } inline int find(int x){ if(x==f[x])return x; int t=f[x];//記錄之前父親 f[x]=find(f[x]);//並查集find dis[x]+=dis[t];//累加距離 return f[x]; } inline void init(){ memset(dis,0,sizeof(dis)); for(int i=1;i<=n;++i)f[i]=i; } int main(){ read(t); while(t--){ read(n); init(); while(1){ cin>>s; if(s[0]=='O')break; if(s[0]=='I'){ read(x); read(y); f[x]=y; dis[x]+=abs(x-y)%1000; }else{ read(x); find(x); printf("%d\n",dis[x]); } } } return 0; }
留一道例題,筆者之后補題解。