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、水果姐逛水果街 ×

  • 相关阅读:
    codeforces 459 B.Pashmak and Flowers 解题报告
    poj 1789 Truck History 解题报告
    poj 1258 Agri-Net 解题报告
    poj 1860 Currency Exchange 解题报告
    poj 1094 Sorting It All Out 解题报告
    poj 3368 Frequent values 解题报告
    hdu 1548 A strange lift 解题报告
    BestCoder4 1002 Miaomiao's Geometry (hdu 4932) 解题报告
    hdu 1400 Mondriaan's Dream 解题报告
    打电话主要代码(意图用法)
  • 原文地址:https://www.cnblogs.com/ExileValley/p/7762516.html
Copyright © 2011-2022 走看看