並查集學習筆記

2021-09-26 19:47:08 字數 2758 閱讀 8546

也算是磕磕絆絆,斷斷續續的學歷一段時間並查集了吧,也是時候改寫乙個blog總結一下啦。

先說一下普通並查集吧。

普通並查集就是單純的把某些可以連起來的點用一條有向邊連起來,表示他們屬於「一類」,例如hdu1213,這就是乙個並查集的裸題,直接把輸入的點合併,之後統計有幾個點的祖先是自己就行。

ac**:

#include#includeusing namespace std;

const int maxn=10010;

int f[maxn];

void init(int n)

int find(int x)

void merge(int x,int y)

}int main()

int ans=0;

for(int i=1;i<=n;i++)

printf("%d\n",ans);

}return 0;

}

還有乙個例子就是hdu3635,這個很容易看出是乙個並查集的題,但這個涉及到三個操作,乙個是查詢x的祖先,乙個是查詢x的祖先所在的位置含有的龍珠的個數,還有乙個就是查詢x一共轉移了幾次。第乙個就是乙個基礎的find操作,第二個直接定義乙個sum陣列,在merge的時候把子節點的sum全部給父節點,並將子節點的sum清為0,最後直接查詢就行,主要是最後乙個,我考慮的是並查集維護的是乙個樹(或者說森林),find操作向上查詢了多少次,這顆龍珠就被轉移了多少次,但這樣就必須把路徑壓縮給去掉,所幸資料範圍比較小,就卡過去啦;

ac**:

#include#include#includeusing namespace std;

const int maxn=10010;

int n,m;

int f[maxn],sum[maxn];

int ans;

void init(int n)

}int find(int x)

}void merge(int x,int y)

}int main()

else}}

return 0;

}

當然,一般比賽的時候很少可以看到某個演算法的裸題,有些並查集的題要構建出並查集的模型才行。

例poj1456,看到這題可以想到貪心,但由於資料範圍很小,時限很多,直接暴力做不會超時,但這一題其實是可以用並查集來優化的。我們排序完之後遍歷時最消耗時間就是去查詢從d -> 1哪乙個點還沒有用,那我們就可以考慮並查集,每次將t-1更新為t的父節點,那們每次find操作只要得到的t不為0就可以更新答案。

ac**:

#include#include#includeusing namespace std;

#define ll long long

const int maxn=10010;

struct node

a[maxn];

bool cmp(node aa,node bb)

int f[maxn];

int find(int x)

void init(int n)

}int main()

init(pos);

sort(a+1,a+n+1,cmp);

ll ans=0;

for(int i=1; i<=n; i++)

}printf("%lld\n",ans);

}return 0;

}

而普通並查集在圖論裡的操作還有很多,比如判斷圖是否連通,判斷圖里有沒有環。。。這裡就不一一贅述。

接下來講一下並查集的公升級版,帶權並查集。

就直接更具題目來講吧

poj1182,這是一道帶權並查集的經典題啦。首先我們用0表示x和y是同類,1表示x吃y,2表示x被y吃。那麼根據向量的運算法則,我們就可以把路勁壓縮和merge操作時的表示式給寫出來,這樣這題就可以做出來啦。

ac**:

#include#include#includeusing namespace std;

const int maxn=5e4+7;

int f[maxn],rank[maxn];

void init(int n)

}int find(int x)

}void merge(int x,int y,int val)

}int main()

int t1=find(x),t2=find(y);

int temp;

if(t1==t2)

else

}else

}printf("%d\n",ans);

return 0;

}

帶權並查集還有區間形的,例如這道題hdu3038,我們每次用(x-1,y]來記錄x->y之間的值,還是一樣,直接在路徑壓縮和merge操作時根據向量運算法則寫出表示式就行。

ac**:

#include#includeusing namespace std;

#define ll long long

const ll maxn=200010;

int f[maxn];

ll rank[maxn];

void init(int n)

}int find(int x)

}int main()

else

}else}}

printf("%lld\n",ans);

}return 0;

}

並查集學習筆記

並查集是一種用來管理資料分組狀況的資料結構,可以進行合併操作,但無法進行分割。並查集的結構 並查集也是用樹形結構來實現的,但不是二叉樹。每個資料,元素對應乙個節點,每個組對應一棵樹。並查集的實現 並查集有幾個基本操作初始化 查詢樹的根 合併x,y所屬集合 判斷x,y是否屬於同一集合。查詢是查詢樹的根...

並查集 學習筆記

並查集是由一組互不相交的集合組成的乙個集合結構,並在此集合上定義了運算union和find。即並查集中的元素本身是集合,他們是某個集合的子集,並查集是由這些集合組成的集合結構。並查集上有兩個最基本的運算,find和union。函式find搜尋給定元素i所在的子集合,並返回該自己喝 union運算將兩...

學習筆記 並查集

這是乙個可以實現合併與查詢 元素間關係判定 用來維護多集合 功能多樣化 的超牛批的可以動態維護的樹形結構。這個演算法只要是實現集合元素關係的型別都可以用到,又是線性時間複雜度,而且最關鍵的是它是個高階資料結構,翻譯過來就是這個可以動態維護,所以我覺得這個用途比單純的演算法要好,實際應用比較大,而且這...