码迷,mamicode.com
首页 > 其他好文 > 详细

倍增法求LCA——在线

时间:2017-10-31 18:40:36      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:例题   str   lock   arch   eid   char   highlight   tar   logs   

 

推荐 B站视频讲解

首先我们考虑暴力做法:

  分别从两个点开始一层一层地向上跳,直到跳到一样的点,这个点就是他俩的LCA了。

这个做法实在太暴力了,不可取,不可取. . .

 

于是我们找到了一个不那么暴力的做法——倍增法。

我们可以用倍增来在线求LCA(其(da)实(gai)就是一跳跳好几层)。

 

fa[i][j] 记录从 i 点向上跳 2j 层所到达的点,fa数组是预处理得出的(还有每个点的深度deep也是),后面会说

_____________先看LCA的求法____________________________________________

我们知道对于两个点的位置有两种情况:

① 位于同一层:

  这时只要两个点一起跳,直到跳到相同的点即可。

for (int i = 20; i >= 0; i--) {
	if (fa[x][i] != fa[y][i]) {
		x = fa[x][i];
		y = fa[y][i];
	}
}

② 不同层:
  将深度更深的点向上跳到与另一个点同一层,即转化为①。

if (node[x].deep < node[y].deep) {
	int t = x;                      // 保证 x 是更深的那个点
	x = y;
	y = t;
}	
	
for (int i = 0; i <= 20; i++) {
	if ((node[x].deep - node[y].deep)>> i & 1) x = fa[x][i];
}
	
if (x == y) return x;                    // 特判:两个点在同一条链上的情况(即:它们其中一个点就是它俩的LCA)

 

______________预处理__________________________________________________

一个 dfs 搞定(从根结点开始DFS)。

void dfs(int s) {	
	for (int k = 1; k <= 20; k++)							 
        fa[s][k] = fa[fa[s][k - 1]][k - 1];
	
	for (Edge *e = node[s].last; e; e = e->next) {
		if (!e->to->deep) {
			e->to->deep = node[s].deep + 1;
			fa[e->to->ma][0] = node[s].ma;
			dfs(e->to->ma);
		} 
	}
}

 

完整代码:

 例题codevs 1036 商务旅行

#include <cstdio>

const int MAXN = 30007;

int n, m, fa[MAXN][30], a[MAXN], ans;

/**********************快********************************/
int read() {
	int x = 0;
	char ch = getchar();
	
	while (ch < ‘0‘ || ch > ‘9‘) ch = getchar();
	while (ch >= ‘0‘ && ch <= ‘9‘) x = x * 10 + ch - ‘0‘, ch = getchar();
	
	return x;
}
/************************读******************************/

struct Edge;
struct Node {
	Edge *last;
	int deep, ma;
	bool vis;
} node[MAXN];

struct Edge {
	Node *from, *to;
	Edge *next;
	Edge (Node *from, Node *to) : from(from), to(to), next(from->last) {}
};

void addE(int x, int y) {
	node[x].last = new Edge(node + x, node + y);
	node[y].last = new Edge(node + y, node + x);
}

void dfs(int s) {	
	for (int k = 1; k <= 20; k++)							// 注意!!!! 
        fa[s][k] = fa[fa[s][k - 1]][k - 1];
	
	for (Edge *e = node[s].last; e; e = e->next) {
		if (!e->to->deep) {
			e->to->deep = node[s].deep + 1;
			fa[e->to->ma][0] = node[s].ma;
			dfs(e->to->ma);
		} 
	}
}

int lca (int x, int y) {
	if (node[x].deep < node[y].deep) {
		int t = x;
		x = y;
		y = t;
	}	
	
	for (int i = 0; i <= 20; i++) {
		if ((node[x].deep - node[y].deep)>> i & 1) x = fa[x][i];
	}
	
	if (x == y) return x;
	
	for (int i = 20; i >= 0; i--) {
		if (fa[x][i] != fa[y][i]) {
			x = fa[x][i];
			y = fa[y][i];
		}
	}
	
	return fa[x][0];
}

int main() {
	n = read(); 

	for (int i = 1; i <= n; i++) node[i].ma = i;

	for (int i = 1, b, c; i < n; i++) {
		c = read();
		b = read();
		addE(c, b);
	}
	
	fa[1][0] = 1;
	node[1].deep = 1;
	dfs(1);

	m = read();
	for (int i = 1; i <= m; i++) {
		a[i] = read();
	}

	for (int i = 2; i <= m; i++) {
		ans += node[a[i]].deep + node[a[i - 1]].deep - 2 * node[lca(a[i - 1], a[i])].deep;
	}

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

	return 0;
}

  

倍增法求LCA——在线

标签:例题   str   lock   arch   eid   char   highlight   tar   logs   

原文地址:http://www.cnblogs.com/ExileValley/p/7762516.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!