给定一棵包含N个节点的带权树,节点编号1~N。小Hi每次会给定树上两个节点的编号u和v,请你计算从u到v的路径上,哪条边的权值最小。

请你输出最小的权值。

输入
第一行包含两个整数N和Q,代表节点数和询问次数。

以下N行每行包含一个整数Pi, Wi,代表1~N的父节点的编号,以及(i, P[i])这条边的权值。其中根的父节点编号为0,这一行的Wi也为0。

以下Q行每行包含两个整数u和v,代表一个询问。

1 <= N, Q <= 100000 1 <= u, v <= N 0 <= Wi <= 1000000000

题解:求树上的两点间的最小值,我们可以想求出两点间的LCA,然后倍增的求出

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int head[maxn], tot;
int lg[maxn + 5];
int depth[maxn + 5], dp[maxn][22];
int father[maxn + 5][22];
int p[maxn], w[maxn];
int n, m, x;
struct Edge {
    int u, v, w, next;
}edge[maxn];

void init() {
    memset(head, -1, sizeof(head)); tot;
}

void add(int u, int v, int w) {
    edge[++tot].u = u; 
    edge[tot].w = w;
    edge[tot].v = v; 
    edge[tot].next = head[u]; head[u] = tot;
}

void dfs(int u, int fa) { //dfs预处理
    depth[u] = depth[fa] + 1;
    father[u][0] = fa;
    for(int j = 1; j <= lg[depth[u]] + 1; j++) {
        father[u][j] = father[father[u][j - 1]][j - 1];
        dp[u][j] = min(dp[u][j - 1], dp[father[u][j - 1]][j - 1]);
    }
    for (int i = head[u]; i  != -1; i = edge[i].next) {
        int to = edge[i].v;
        if (to == fa) {
            continue;
        }
        dp[to][0] = edge[i].w;
        dfs(to, u);
    }
}
int LCA(int u, int v) { //求LCA
    if(depth[u] < depth[v]) {
        swap(u, v);
    }
    while(depth[u] != depth[v]) {
        u = father[u][lg[depth[u] - depth[v]]];
    }
    if(u == v) {
        return u;
    }
    for(int j = lg[depth[u]]; j >= 0; j--) {
        if(father[u][j] != father[v][j]) {
            u = father[u][j];
            v = father[v][j];
        }
    }
    return father[u][0];
}

int getAns(int u, int lca) { //每次都进行一次倍增zhi'dao
    int k = lg[depth[u] - depth[lca]];
    if (father[u][k] == lca) return dp[u][k];
    return min(dp[u][k], getAns(father[u][k], lca));

}

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 2; i <= n; i++) {
        lg[i] = lg[i >> 1] + 1;
    }
    init();
    for (int i = 1; i <= n; i++) {
        scanf("%d%d", &p[i], &w[i]);
        add(i, p[i], w[i]); add(p[i], i, w[i]);
    }
    dfs(0, 0);
    int u, v;
    while (m--) {
        scanf("%d%d", &u, &v);
        if (u == v) {
            printf("0\n"); continue;
        }
        int lca = LCA(u, v);
        if (lca == u) {
            int k = lg[depth[v] - depth[lca]];
            printf("%d\n", getAns(v, lca));
        } else if (lca == v) {
            printf("%d\n", getAns(u, lca));
        } else {
            printf("%d\n", min(getAns(u, lca), getAns(v, lca)));
        }
    }
    return 0;
}