POJ 1330 Nearest Common Ancestors 最近公共祖先

LCA模板题,用倍增法去写
首先把每一个节点的向上\(2^i (i \in \mathbb N)\)个祖先给枚举出来
再把要求公共祖先的两个节点拉到同一深度
向上不断利用倍增一起跳跃同样层数到他们各自的非公共祖先的祖先节点
最后他们一起到达共同祖先节点的子节点,再同时向上走一位即可
在这个过程中,同时维护cost即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;

const int N = 40001;
int p[N][31], cost[N][31], lv[N];
vector<pii> G[N];

int dfs(int x,int fx) {
    p[x][0]=fx;
    lv[x]=lv[fx]+1;
    for(int i=1;i<31;i++) {
        p[x][i]=p[p[x][i-1]][i-1];
        cost[x][i]=cost[p[x][i-1]][i-1]+cost[x][i-1];
    }
    for(auto u:G[x]){
        if(u.first==fx) continue;
        cost[u.first][0]=u.second;
        dfs(u.first,x);
    }
}

int lca(int x,int y) {
    if(lv[x]>lv[y]) swap(x,y);
    int tmp = lv[y]-lv[x], ans = 0;
    for(int i=0;tmp;i++,tmp>>=1)
        if(tmp&1) ans += cost[y][i],y=p[y][i];
    if(y==x) return ans;
    for(int i=30;i>=0&&y!=x;i--) {
        if(p[x][i]==p[y][i]) continue;
        ans+=cost[x][i]+cost[y][i];
        x=p[x][i];
        y=p[y][i];
    }
    ans+=cost[x][0]+cost[y][0];
    return ans;
}

int n,m,a,b,c;

int solve(){
    for(int i=0;i<N;i++) G[i].clear();
    cin>>n>>m;
    for(int i=1;i<n;i++) {
        cin>>a>>b>>c;
        G[a].push_back(make_pair(b,c));
        G[b].push_back(make_pair(a,c));
    }
    dfs(1,0);
    while(m--){
        cin>>a>>b;
        cout<<lca(a,b)<<endl;
    }
}

int main(){
    int t;
    cin>>t;
    while(t--) solve();
}
posted @ 2019-12-29 11:15  潇湘风夜  阅读(120)  评论(0编辑  收藏  举报