倍增法LCA hdu2586 How far away ?

传送门:点击打开链接

题意:给你一棵树,每条边有权值,求两点之间的最短距离

思路:裸LCA。这里主要练习一下倍增法,感觉这种思路和代码实现很简单,而且能感觉实用性很大的,很值得学习

倍增法要理解对2的次方的枚举顺序
如果是要走固定步数,那么顺序枚举与i位与为1就行
如果是要求一个临界位置,那么要从大到小枚举

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;

const int MX = 1e5 + 5;
const int M = 20;

struct Edge {
    int v, nxt, cost;
} E[MX];
int Head[MX], rear;
void edge_init() {
    rear = 0;
    memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v, int cost) {
    E[rear].v = v;
    E[rear].cost = cost;
    E[rear].nxt = Head[u];
    Head[u] = rear++;
}

int dep[MX], dist[MX], fa[MX][M], n;
void DFS(int u, int _dist, int _dep, int _fa) {
    dist[u] = _dist; dep[u] = _dep; fa[u][0] = _fa;
    for(int i = Head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if(v == u || v == _fa) continue;
        DFS(v, _dist + E[i].cost, _dep + 1, u);
    }
}
void presolve() {
    DFS(1, 0, 0, 1);
    for(int i = 1; i < M; i++) {
        for(int j = 1; j <= n; j++) {
            fa[j][i] = fa[fa[j][i - 1]][i - 1];
        }
    }
}
int LCA(int u, int v) {
    while(dep[u] != dep[v]) {
        if(dep[u] < dep[v]) swap(u, v);
        int d = dep[u] - dep[v];
        for(int i = 0; i < M; i++) {
            if(d >> i & 1) u = fa[u][i];
        }
    }
    if(u == v) return u;
    for(int i = M - 1; i >= 0; i--) {
        if(fa[u][i] != fa[v][i]) {
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    return fa[u][0];
}
int query(int u, int v) {
    return dist[u] + dist[v] - dist[LCA(u, v)] * 2;
}

int main() {
    int T, m; //FIN;
    scanf("%d", &T);
    while(T--) {
        edge_init();
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n - 1; i++) {
            int u, v, cost;
            scanf("%d%d%d", &u, &v, &cost);
            edge_add(u, v, cost);
            edge_add(v, u, cost);
        }
        presolve();

        while(m--) {
            int u, v;
            scanf("%d%d", &u, &v);
            printf("%d\n", query(u, v));
        }
    }
    return 0;
}


你可能感兴趣的:(倍增法LCA hdu2586 How far away ?)