以前了解的tarjin演算法是用來求連通分量,在這裡是用來求最近公共祖先
並查集用過,很有意思的工具。kraskal演算法是並查集最經典的應用。首先初始化集合,每個元素為單個集合。集合,我們需要選出乙個代表,這個代表的性質是set[u] = u。一開始乙個集合只有乙個元素,所以該集合的代表也就是該元素。當兩個集合需要合併時,例如:set[a] = a, set[b] = b。要是把a當作合併後集合的代表,那就讓set[b] = a。這樣,在find函式中,當發現set[u] != u時,意思就是,u這個元素,是和set[u]這個元素屬於同一集合,然後就遞迴查詢,直到set[v] = v,然後回退,更新set[u]。這個步驟叫做「路徑壓縮」。例如,set[a] = b; set[b]=c; set[c]=d;...., set[y] = z, set[z]=z,當開始find(a)後,會逐步深入到set[z]=z停止,然後回退,令set[y] = z, set[x] = z, set[w] = z, ... set[a] = z,這樣,下次再find(a)時,就能很快找到set[z]=z結束,路徑是不是變短了呢。
先看一下這個參考資料:
這裡去掉了參考資料中的ancestor陣列。直接用子樹的根節點來做集合的代表。從乙個節點,走到另乙個節點,必然要經過而且最先經過這兩個節點的最近公共祖先。所以當發現乙個節點a訪問了時,馬上查詢另乙個另乙個節點b,如果該節點已訪問,那b所在集合的代表,就是a和b的最近公共祖先。
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define m 50
#define c 50
#define q 50
typedef struct _nodenode, *pnode;
typedef struct _queryquery, *pquery;
query que[q];
int n, q;
int set[m];
int mk[m];
pnode root;
void init()
}void show(pnode r)
void lca(pnode r)
mk[r->data] = 1;
for(i=0; idata==que[i].s && mk[que[i].e])
t = que[i].e;
else if(r->data==que[i].e && mk[que[i].s])
t = que[i].s;
if(t!=-1)
que[i].anc = find(t); }}
void main(){
int i;
freopen("in.txt", "r", stdin);
while(scanf("%d %d", &n, &q)!=eof){
init();
root = 0;
create(&root);
for(i=0; i資料:
20 19
0 21 3
3 04 2
8 212 0
13 0
9 214 0
15 0
5 210 2
16 0
17 0
11 2
18 0
19 0
2 26 0
7 08 5
12 14
14 6
6 710 9
3 10
14 15
15 8
11 10
13 12
5 418 13
4 17
16 19
9 19
10 19
7 17
17 16
18 19
離線 並查集 Mootube
mootube 描述給定一顆n個節點的樹,定義兩點距離為他們之間路徑中邊權最小值。q次詢問k,v,詢問到v距離 k的點有多少 不含v 輸入第一行兩個整數n,q。接下來n 1行,每行3個整數u,v,w表示u,v之間有條路徑,長為w 接下來q組詢問,每組詢問2個整數k,v 輸出q行回答詢問 樣例輸入 4...
題解 history(離線並查集)
今天考試很水,ssw023道題都寫的正解,然而不注重細節。1or 1寫成 1 連通塊最大值不更新 t3就是這道細節題 description 歷史學家小 正在研究乙個奇怪的王國的歷史。當前階段的任務是研究該國的交通。根據這個奇怪的王國的史書記載,史書開始記載前這個王國有 n 個城市 城市從 0 開 ...
並查集 並查集
本文參考了 挑戰程式設計競賽 和jennica的github題解 陣列版 int parent max n int rank max n void init int n int find int x else void union int x,int y else 結構體版 struct node ...