LCA 倍增模版

倍增算法可以在线求树上两个点的LCA,时间复杂度为nlogn

预处理:通过dfs遍历,记录每个节点到根节点的距离dis[u],深度dep[u]

i的2^j祖先就是i的(2^(j-1))祖先的2^(j-1)祖先:

///倍增算法
const int maxn = 1e5 + 10;
int dis[maxn];            ///与根节点的距离
int dep[maxn];            ///深度
int fa[maxn][25];         /// fa[i][j] 表示 i 节点的第 2^j 的祖先
int n,m;        ///其中 m = log(n * 1.0) / log(2.0);  n 为总数,编号为 1 ~ n;
struct node{
    int v,w;
};
vector<node>edges[maxn*2];  ///存放树,放双向边

void dfs(int f,int s,int w){
    if(f != s) dep[s] = dep[f] + 1, dis[s] = dis[f] + w;
    for(int j = 0;j < edges[s].size();j ++){
        int v = edges[s][j].v;
        if(v != f){
            fa[v][0] = s;
            for(int i = 1;i <= m;i ++)
                fa[v][i] = fa[fa[v][i-1]][i-1];
            dfs(s,v,edges[s][j].w);
        }
    }
}

int lca(int u,int v){
    if(dep[u] < dep[v]) swap(u,v);      ///u 在下面
    int d = dep[u] - dep[v];
    for(int i = 0; (1 << i) <= d;i ++)      ///移动到相同深度
        if((1 << i) & d)                ///(1<<i)&f找到f化为2进制后1的位置,移动到相应的位置
            u = fa[u][i];               ///比如f=5(101),先移动2^0祖先,然后再移动2^2祖先

    if(u != v){
        for(int i = m;i >= 0;i --)
            if(fa[u][i] != fa[v][i])         ///从最大祖先开始,判断a,b祖先,是否相同
                u = fa[u][i], v = fa[v][i];  ///如不相同,a b同时向上移动2^j
        u = fa[u][0];
    }
    return u;
}

int main()
{
    int n; scanf("%d",&n);
    m = log(n*1.0) / log(2.0);
    for(int i = 0;i <= n;i ++) edges[i].clear();
    
    dis[1] = 0; dep[1] = 0;
    /// 输入树
    
    
    dfs(1,1,0);
    int q; scanf("%d",&q);         ///q 次查询
    while(q --){
        int x,y; scanf("%d%d",&x,&y);
        int LCA = lca(x,y);
        printf("LCA is %d , and the dis is %d",LCA,dis[x] + dis[y] - 2 * dis[LCA]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值