ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LCA

2022-05-14 15:32:13  阅读:6  来源: 互联网

标签:nxt int up dep LCA now ds


最近公共祖先 LCA

dfs向上标记-O(n)

点A先向根搜索并标记,点B再向上搜索,第一次碰到的标记即是lca。

复杂度On,不常用

倍增法-O(logn)

dep[i]表示点i的深度
up[i,j]表示从i开始向root方向走2^j步数能走到的位置
若从i开始向根跳2^j次会跳出根则up[i,j]=0,dep[0]=0
具体过程:
【1】先让两点跳到同一层
【2】让两个点一起向根跳,直到跳到他们lca的下一层(一定要是下一层)

其中,从点i向根跳2j步等价于从点i跳2(j-1)次后再跳2^(j-1)次。如下图:

vct<ll> eg[N] ;
int dep[N] ;
int up[N][16] ;

void init(){
    memset(dep , N , sizeof dep) ;
    dep[root] = 1 ;
    dep[0] = 0 ;
    queue<int> q ;
    q.push(root) ;

    while(q.size()){
        int now = q.front() ;
        q.pop() ;
        for(int nxt : eg[now]){
            if(dep[nxt] > dep[now] + 1){
                dep[nxt] = dep[now] + 1 ;
                q.push(nxt) ;

                up[nxt][0] = now ;
                rep(i , 1 , 15){
                    up[nxt][i] = up[up[nxt][i - 1]][i - 1] ;
                }
            }
        }
    }

}

int lca(int a , int b){
    if(dep[a] < dep[b]) swap(a , b) ;

    drep(i , 0 , 15)//将ab放到同一层 
    if(dep[up[a][i]] >= dep[b])
        a = up[a][i] ;

    if(a == b) return b ;

    drep(i , 0 , 15)//一起向上跳 
    if(up[a][i] != up[b][i]){
        a = up[a][i] ;
        b = up[b][i] ;
    }
    return up[a][0] ;
}

Tarjan离线lca-O(n+m)

根据dfs性质,搜索点i的时候会将点u的所有子树也搜索完。而我们可以在搜索完点u的子树的时候将和点i相关的query全部找一遍,若存在某个query其另一个点(点v)被搜索过,那么uv两点的LCA就是点v在并查集中的祖先。

题目传送门

/*
本代码用于求解任意树上两点的距离
acwing-1171-距离
*/

ll n , m , k ; 

struct edge{
    ll idx , len ;
};

vct<pii> query[N] ;

vct<edge> eg[N] ;

int ds[N] , ans[N] ;
int vis[N] , fa[N] ;

int find(int now){
    return fa[now] = fa[now] == now ? now : find(fa[now]) ;
}

void dfs(int now , int pre){//初始化每个点到根的距离
    //由于树是一个拓扑图,只要简单搜索即可
    for(auto e : eg[now]){
        int nxt = e.idx ;
        int val = e.len ;
        if(nxt == pre) continue ;
        ds[nxt] = ds[now] + val ;
        dfs(nxt , now) ;
    }
}

void tarjan(int now){
    vis[now] = 1 ;
    for(auto e : eg[now]){
        int nxt = e.idx ;
        if(vis[nxt]) continue ;
        tarjan(nxt) ;
        fa[nxt] = now ;
    }
    for(auto q : query[now]){//和点now有关的所有询问
        int idx = q.se ;
        int node = q.fi ;
        if(vis[node] == 0) continue ;
        int lca = find(node) ;
        ans[idx] = ds[node] + ds[now] - 2 * ds[lca] ;
    }
    vis[now] = 1 ;
}

void solve(){
    cin >> n >> m ;

    rep(i , 1 , n) fa[i] = i ;
    rep(i , 1 , m) ans[i] = -1 ;
    rep(i , 1 , n - 1){
        ll u , v , w ;
        cin >> u >> v >> w ;
        if(u == v) continue ;
        eg[u].pb({v , w}) ;
        eg[v].pb({u , w}) ;
    }
    rep(i , 1 , m){
        int u , v ;
        cin >> u >> v ;
        query[u].pb({v , i}) ;
        query[v].pb({u , i}) ;
    }

    ds[1] = 0 ;
    dfs(1 , -1) ;

    tarjan(1) ;

    rep(i , 1 , m) cout << ans[i] << "\n" ;

}//code_by_tyri

标签:nxt,int,up,dep,LCA,now,ds
来源: https://www.cnblogs.com/tyriis/p/16270247.html

专注分享技术,共同学习,共同进步。侵权联系[admin#icode9.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有