LCA Tarjin 並查集 離線

以前瞭解的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結束,路徑是不是變短了呢。

“離線”的意思是,需要預先知道所有的提問。那“在線”的意思就是不需要提前知道問題,你隨便問,即刻回答。


先看一下這個參考資料:http://blog.csdn.net/ljsspace/article/details/66910300

這裏去掉了參考資料中的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 _Node{
	int data;
	int chs;
	struct _Node* ch[C];
}Node, *pNode;

typedef struct _Query{
	int s, e;
	int anc;
}Query, *pQuery;
Query que[Q];

int n, q;
int set[M];
int mk[M];

pNode root;

void init(){
	int i;
	for(i=0; i<n; i++)
		set[i] = i;
}

int find(int u){
	if(u!=set[u])
		set[u] = find(set[u]);
	return set[u];
}

void combine(int u, int v){
	set[v] = u;
}

void create(pNode* r){
	int i;
	int v, c;
	scanf("%d %d", &v, &c);
	*r = (pNode)malloc(sizeof(Node));
	(*r)->data = v;
	(*r)->chs = c;
	for(i=0; i<c; i++){
		create(&((*r)->ch[i]));
	}
}

void show(pNode r){
	int i;
	printf("%d ", r->data);
	for(i=0; i<r->chs; i++)
		show(r->ch[i]);
}

void LCA(pNode r){
	int i;
	int t;
	for(i=0; i<r->chs; i++){
		LCA(r->ch[i]);
		combine(r->data, r->ch[i]->data);
	}
	mk[r->data] = 1;
	for(i=0; i<q; i++){
		t = -1;
		if(r->data==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<q; i++){
			scanf("%d %d", &(que[i].s), &(que[i].e));
		}
		memset(mk, 0, sizeof(mk));
		LCA(root);
		
		for(i=0; i<q; i++)
			printf("LCA of %d and %d is: %d\n", que[i].s, que[i].e, que[i].anc);
	}
}

數據:

20 19
0 2
1 3
3 0
4 2
8 2
12 0
13 0
9 2
14 0
15 0
5 2
10 2
16 0
17 0
11 2
18 0
19 0
2 2
6 0
7 0
8 5
12 14
14 6
6 7
10 9
3 10
14 15
15 8
11 10
13 12
5 4
18 13
4 17
16 19
9 19
10 19
7 17
17 16
18 19

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章