• 模板: 最近公共祖先(倍增实现) LCA-Doubling


    Lowest Common Ancestors (LCA)-Doubling

    最近公共祖先(倍增实现)

    模板题

    Brief Introduction

    在图论和CS中,两个节点(v)(w)在树上或者有向无环图中的最近公共祖先(LCA)(T)是指,同时拥有(v)(w)这两个节点作为后代的最深的节点。我们定义每个节点也是其本省的后代(所以如果(v)(w)的后代,(w)就是它们的最近公共祖先)

    In graph theory and computer science, the lowest common ancestor (LCA) of two nodes v and w in a tree or directed acyclic graph (DAG) T is the lowest (i.e. deepest) node that has both v and w as descendants, where we define each node to be a descendant of itself (so if v has a direct connection from w, w is the lowest common ancestor).

    Algorithm

    本文介绍求LCA在线算法中的倍增实现,初始化复杂度(O(n)),单次查询复杂度(O(log n))

    算法的核心在于ST表,用 ( ext S ext T[cur][i]) 数组存放 (cur) 节点的第(2^i)辈祖先。

    用DFS从根遍历初始化,打表转移方程( ext S ext T[cur][i]= ext S ext T[ ext S ext T[cur][i-1]][i-1])。 复杂度(O(log n))

    询问时,先将(u)(w)某一个更深的点,利用ST表,向祖先移动至同样深度。

    如果此时(u=w)则该节点便是 LCA,

    否则同样深度下(u ot=w),则用ST表从最深的深度递减试探,将(u,w)在ST表移动至最浅的祖先在同样深度下,(u ot=w)的节点,它们的父节点便是所求LCA。

    Template Code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MAXN 500005
    #define MAXM 500005
    #define MAXLN 25
    using namespace std;
    
    struct edge{
    	int to,next;
    }e[MAXM<<1];
    
    int tot,head[MAXN];
    
    void add(int x,int y){
    	tot++;
    	e[tot].to=y;
    	e[tot].next=head[x];
    	head[x]=tot;
    }
    
    int dep[MAXN],lgd[MAXN],st[MAXN][MAXLN];
    
    void dfs(int cur,int fa){
    	dep[cur]=dep[fa]+1;
    	st[cur][0]=fa;
    	for(lgd[cur]=1;(1<<lgd[cur])<=dep[cur];lgd[cur]++)
    		st[cur][lgd[cur]]=st[st[cur][lgd[cur]-1]][lgd[cur]-1];
    
    	for(int p=head[cur];p;p=e[p].next){
    		if(e[p].to==fa) continue;
    		dfs(e[p].to,cur);
    	}
    }
    
    int lca(int x,int y){
    	if(dep[x]<dep[y]) swap(x,y);
    	for(int i=0;dep[x]-dep[y];i++)
    		if((dep[x]-dep[y])&(1<<i)) x=st[x][i];
    	if(x==y) return x;
    	
    	for(int i=lgd[x];i>=0;i--)
    		if(st[x][i]!=st[y][i])
    			x=st[x][i], y=st[y][i];
    	return st[x][0];
    }
    
    int n,m,s;
    
    int main(){
    	scanf("%d %d %d", &n, &m, &s);
    	tot=0;
    	memset(head+1,0,n*sizeof(head[0]));
    	for(int i=1;i<n;i++){
    		int f,g;
    		scanf("%d %d", &f, &g);
    		add(f,g);
    		add(g,f);
    	}
    	dep[0]=0;
    	dfs(s,0);
    	for(int i=1;i<=m;i++){
    		int f,g;
    		scanf("%d %d", &f, &g);
    		printf("%d
    ", lca(f,g));
    	}
    	return 0;
    }
    
  • 相关阅读:
    [ZJOI2010]基站选址
    [SDOI2008]Sue的小球
    访问计划
    奥义商店
    codeforces 809E Surprise me!
    codeforces 888G Xor-MST
    [HAOI2015]数字串拆分
    小奇分糖果
    小奇的花园
    BZOJ4711 小奇挖矿
  • 原文地址:https://www.cnblogs.com/leachim/p/12362207.html
Copyright © 2020-2023  润新知