• 倍增算法


    1.求LCA

    首先求出每个节点的深度, 如果我们要求u, v 的LCA

    首先找到 u 的一个和 v 在同一深度的祖先 u’ , 则 LCA(u, v) = LCA(u’ , v)

    若 u’ = v , 说明 u’ 正好就是LCA(u, v) , 否则:

    • u’, v 两个点同时向上跳 2j 步,
      1. 若指向同一个点, 说明他们距离LCA小于等于 2j , 此时我们减少上跳幅度
      2. 若指向不同的点, 重复 1, 2, 直到 j = 0, 再跳一步, 正好到达 LCA

    算法步骤

    1. dfs预处理, f[i][j] 表示 i 的 2j 级祖先
    void dfs(int u,int fa){
        dep[u]=dep[fa]+1;//当前节点深度为父节点深度 +1
        for(int i=1;(1<<i)<=dep[u];i++)
            f[u][i]=f[f[u][i-1]][i-1];//根据u的深度,预处理其2^i祖先 
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(v==fa)continue;
            f[v][0]=u;//v的父亲节点是u 
            dfs(v,u);
        }
    }
    

    2.上调至同一深度

    u, v不在同一个深度时,我们要用倍增思想把深度大的节点u调到和v在同一个深度。

    int len=dep[u]-dep[v],k=0;
    while(len){//对k进行二进制分解
        if(len & 1) u=f[u][k];//如果当前位为1
        ++k;len>>=1;//k记录处理到 len 的第几个二进制位
    
    1. 代码全貌
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e4+5,maxe=1e5+5;
    int n, len, head[maxn], dep[maxn], f[maxn][21];
    struct edge{
    	int next,to;
    }e[2*maxe];
    void Insert(int u,int v){
    	e[++len].to=v;
        e[len].next=head[u];
        head[u]=len;    
    }
    void dfs(int u,int fa){
        dep[u] = dep[fa] + 1;
    	for(int i=1; i<=dep[u]; i++) f[u][i] = f[f[u][i-1]][i-1];
    	for(int i=head[u]; i; i=e[i].next){
    		int v = e[i].to;
    		if(v == fa) continue;
    		dfs(v, u);
    		f[v][0] = u;
    	}
    }
    int lca(int u,int v){
        if(dep[u] < dep[v]) swap(u, v);
    	int len = dep[u] - dep[v], k = 0;
    	while(len){
    		if(len & 1) u = f[u][k];
    		k++; len >>= 1;
    	}
    	if(u == v) return u;
    	for(int i=20; i>=0; i--){
    		if(f[u][i] == f[v][i]) continue;
    		u = f[u][i]; v = f[v][i];
    	}
    	return f[u][0];
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int x,y;scanf("%d%d",&x,&y);
            Insert(x,y);Insert(y,x);
        }
        dfs(1,0);
        int Q;scanf("%d",&Q);
        for(int i=1;i<=Q;i++){
            int u,v;scanf("%d%d",&u,&v);
            printf("%d
    ",dep[u]+dep[v]-2*dep[lca(u,v)]);//求两个节点的LCA 
        }
    }
    
  • 相关阅读:
    (转)Mat, vector<point2f>,Iplimage等等常见类型转换
    人脸检测与识别的趋势和分析
    经典网络LeNet5看卷积神经网络各层的维度变化
    C++: int int& int * int**的区别、联系和用途
    c++从txt中读取数据,数据并不是一行路径(实用)
    Spyder常用快捷键
    批量读写变换图片(转)
    OpenCV属性页配置问题~
    视觉目标检测和识别之过去,现在及可能(2017.06.28)
    数据库---SQL Server
  • 原文地址:https://www.cnblogs.com/hzoi-poozhai/p/12817530.html
Copyright © 2020-2023  润新知