zoukankan      html  css  js  c++  java
  • 倍增法求LCA——在线

     B站视频讲解

    首先暴力做法:

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

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

    有一个不那么暴力的做法——倍增法。

    预处理复杂度:O(nlogn)

    询问复杂度:O(Qlogn)    Q : 询问组数 

    其(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
    ", ans);
    
    	return 0;
    }
    

    例题:

    1、商务旅行 √

    2、小机房的树 √

    3、水果姐逛水果街 ×

  • 相关阅读:
    结巴分词 0.14 版发布,Python 中文分词库
    Lazarus 1.0.2 发布,Pascal 集成开发环境
    Android全屏 去除标题栏和状态栏
    服务器日志现 Android 4.2 传将添多项新特性
    Percona XtraBackup 2.0.3 发布
    长平狐 Android 强制设置横屏或竖屏 设置全屏
    NetBeans 7.3 Beta 发布,全新的 HTML5 支持
    CppDepend现在已经支持Linux
    GromJS 1.7.18 发布,服务器端的 JavaScript
    Apache OpenWebBeans 1.1.6 发布
  • 原文地址:https://www.cnblogs.com/ExileValley/p/7762516.html
Copyright © 2011-2022 走看看