1. 程式人生 > >備戰NOIP——模板複習9

備戰NOIP——模板複習9

這裡只有模板,並不作講解,僅為路過的各位做一個參考以及用做自己複習的資料,轉載註明出處。

最近公共祖先(LCA)

樹鏈剖分

/*Copyright: Copyright (c) 2018
*Created on 2018-10-28  
*Author: 十甫
*Version 1.0 
*Title: LCA_樹鏈剖分
*Time: 8.5 mins
*/
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 10005;

int head[maxn];
struct edge {
	int to, next;
} data[maxn * 2];
inline void add_edge(int from, int to, int i) {
	data[i] = (edge) {to, head[from]};
	head[from] = i;
}
int depth[maxn], f[maxn], son[maxn], top[maxn], size[maxn];
void dfs1(int pos, int d) {
	size[pos] = 1, depth[pos] = d;
	for(int i = head[pos];i;i = data[i].next) {
		int u = data[i].to;
		if(u == f[pos]) continue;
		f[u] = pos;
		dfs1(u, d + 1);
		size[pos] += size[u];
		if(size[u] > size[son[pos]]) son[pos] = u;
	}
}
void dfs2(int pos, int t) {
	top[pos] = t;
	if(son[pos]) dfs2(son[pos], t);
	for(int i = head[pos];i;i = data[i].next) {
		int u = data[i].to;
		if(u == f[pos] || u == son[pos]) continue;
		dfs2(u, u);
	}
}
int lca(int a, int b) {
	while(top[a] != top[b]) {
		if(depth[top[a]] < depth[top[b]]) swap(a, b);
		a = f[top[a]];
	}
	return depth[a] > depth[b] ? b : a;
}

int main() {
	int n;
	scanf("%d", &n);
	for(int i = 1;i < n;i++) {
		int a, b;
		scanf("%d%d", &a, &b);
		add_edge(a, b, i), add_edge(b, a, i + n);
	}
	dfs1(1, 1);
	dfs2(1, 1);
	int q;
	scanf("%d", &q);
	while(q--) {
		int a, b;
		scanf("%d%d", &a, &b);
		printf("%d\n", lca(a, b));
	}
	return 0;
}

倍增

/*Copyright: Copyright (c) 2018
*Created on 2018-10-28  
*Author: 十甫
*Version 1.0 
*Title: LCA_倍增
*Time: 10 mins
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int size = 10005;
const int maxk = 20;

int head[size];
struct edge {
	int to, next;
} data[size * 2];
inline void add_edge(int from, int to, int i) {
	data[i] = (edge) {to, head[from]};
	head[from] = i;
}
int book[maxk][size], depth[size];
void dfs(int pos, int d) {
	depth[pos] = d;
	for(int i = head[pos];i;i = data[i].next) {
		int u = data[i].to;
		if(u == book[0][pos]) continue;
		book[0][u] = pos;
		dfs(u, d + 1);
	}
}
void make(int n) {
	for(int k = 1;(1 << k) <= n;k++) {
		for(int i = 1;i <= n;i++) {
			book[k][i] = book[k - 1][book[k - 1][i]];
		}
	}
}
inline int lca(int a, int b) {
	if(depth[a] < depth[b]) swap(a, b);
	for(int k = maxk - 1;k >= 0;k--) {
		if(depth[book[k][a]] >= depth[b]) {
			a = book[k][a];
		}
	}
	if(a == b) return a;
	for(int k = maxk - 1;k >= 0;k--) {
		if(book[k][a] != book[k][b]) {
			a = book[k][a], b = book[k][b];
		}
	}
	return book[0][a];
}

int main() {
	int n;
	scanf("%d", &n);
	for(int i = 1;i < n;i++) {
		int a, b;
		scanf("%d%d", &a, &b);
		add_edge(a, b, i), add_edge(b, a, i + n);
	}
	dfs(1, 1);
	make(n);
	int q;
	scanf("%d", &q);
	while(q--) {
		int a, b;
		scanf("%d%d", &a, &b);
		printf("%d\n", lca(a, b));
	}
	return 0;
}