LCA最近公共祖先模板

1.倍增优化LCA

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
//输入
vector<int>G[maxn];
int root;
int V;

int parent[10][maxn];
int depth[maxn];

void dfs(int v,int p,int d){
    parent[0][v] = p;
    depth[v] = d;
    for(int i = 0;i < G[v].size();i++){
        if(G[v][i] != p) dfs(G[v][i],v,d + 1);
    }
}

//预处理
void init(){
    dfs(root,-1,0);
    for(int k = 0;k < 10;k++){
        for(int v = 0;v < V;v++){
            if(parent[k][v] < 0) parent[k + 1][v] = -1;
            else parent[k + 1][v] = parent[k][parent[k][v]];
        }
    }
}

//计算u和v的LCA
int lca(int u,int v){
    if(depth[u] > depth[v]) swap(u,v);
    for(int k= 0;k < 10;k++){
        if((depth[v]-depth[u])>>k&1){
            v = parent[k][v];
        }
    }
    if(u == v) return u;
    for(int k = 10;k >= 0;k--){
        if(parent[k][u] != parent[k][v]){
            u = parent[k][u];
            v = parent[k][v];
        }
    }
    return parent[0][u];
}

int main(){
    return 0;
}

2.基于欧拉序 + RMQ

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;//最大的村庄的个数


int T,n,m;//n个村庄,m次询问

struct Edge{
    int v;
    int w;
    int next;
}edge[maxn * 2];

int edgecount;
int head[maxn];

void add_edge(int u,int v,int w){//加边函数
    edge[++edgecount].v = v;
    edge[edgecount].w = w;
    edge[edgecount].next = head[u];
    head[u] = edgecount;
}

void In(){//输入
    int u,v,k;
    scanf("%d%d",&n,&m);
    for(int i = 1;i < n;i++){
        scanf("%d%d%d",&u,&v,&k);
        add_edge(u,v,k);
        add_edge(v,u,k);
    }
}

void Init(){//初始化
    edgecount = 0;
    memset(head,-1,sizeof(head));
}

int vs[maxn * 2];//dfs访问的顺序,相当于时间戳
int depth[maxn * 2];//节点的深度
int id[maxn * 2];//各个顶点在vs中首次出现的下标

void Dfs(int u,int p,int d,int &x){//???
    id[u] = x;
    vs[x] = u;
    depth[x++] = d;
    for(int k = head[u];k != -1;k = edge[k].next){
        int v = edge[k].v;
        int w = edge[k].w;
        if(v != p){
            Dfs(v,u,d + w,x);
            vs[x] = u;
            depth[x++] = d;
        }
    }
}

int dp[maxn * 2][20];
void RMQ_init(int n){//预处理出数组depth中从1到n的最小值
    for(int i = 1;i <= n;i++) dp[i][0] = i;
    for(int j = 1;(1 << j) <= n;j++){
        for(int i = 1;i + (1 << j) - 1 <= n;i++){
            int x = dp[i][j - 1];
            int y = dp[i +(1 << (j - 1))][j - 1];
            if(depth[x] < depth[y]) dp[i][j] = x;//dp[i][j]存储的是节点编号
            else dp[i][j] = y;
        }
    }
}

int Query(int L,int R){//查询最小值
    int k = log((double)(R - L + 1)) / log(2.0);
    int x = dp[L][k];
    int y = dp[R - (1 << k) + 1][k];
    if(depth[x] < depth[y]) return x;
    else return y;
}

void LCA(){
    int root = 1;
    int k = 1;
    Dfs(root,-1,0,k);
    RMQ_init(2 * n);
}

int main(){
    int a,b;
    scanf("%d",&T);
    while(T--){
        Init();
        In();
        LCA();
        for(int i = 1;i <= m;i++){
            scanf("%d%d",&a,&b);
            int x = Query(min(id[a],id[b]),max(id[a],id[b]));
            cout << depth[id[a]] + depth[id[b]] - 2 * depth[id[vs[x]]] << endl;
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值