感受
深深感觉到我很弱,树上倍增居然可以这样用!




如果想到倍增,应该就可以想到这个DP以及转移式。
但是存在一个问题:如何初始化dp[i][0]呢?








求解完DP后,如何求答案呢?
对于每一个询问q, u, v, c;
我们可以再u的后面加一个点r,然后从r开始往上跳


 #include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
struct edge{
    int v, nex;
}e[maxn << 1];
struct node{
    int u, v;
}b[maxn];
int a[maxn];
int n, q, cnt;
int head[maxn], dep[maxn];
void add_edge(int u, int v){
    cnt++;
    e[cnt] = (edge){v, head[u]};
    head[u] = cnt;
}
int dp[maxn][25];
void dfs(int u, int f, int d){
    dep[u] = d;
    /**
    求解dp[i][j] 从i这个位置再购买2^j的位置
    dp[i][0]
    **/
    if(a[u] < a[f]){
        dp[u][0] = f;
    }
    else{
        int x = f;
        for(int j = 19; j >= 0; j--){
            if(dp[x][j] && a[dp[x][j]] <= a[u]) x = dp[x][j];
        }
        dp[u][0] = dp[x][0];
    }
    for(int j = 1; j <= 19; j++){
        dp[u][j] = dp[dp[u][j - 1]][j - 1];
    }
    for(int i = head[u]; i > 0; i = e[i].nex){
        if(e[i].v == f) continue;
        dfs(e[i].v, u, d + 1);
    }
}
int main(){
    scanf("%d%d", &n, &q);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    int u, v, c;
    for(int i = 1; i < n; i++){
        scanf("%d%d", &u, &v);
        add_edge(u, v); add_edge(v, u);
    }
    for(int i = 1; i <= q; i++){
        scanf("%d%d%d", &u, &v, &c);
        a[n + i] = c;
        add_edge(u, n + i); add_edge(n + i, u);
        b[i] = (node){n + i, v};
    }
    dfs(1, 0, 1);
    int ans;
    for(int i = 1; i <= q; i++){
        u = b[i].u; v = b[i].v; ans = 0;
        for(int j = 19; j >= 0; j--){
            if(dep[dp[u][j]] >= dep[v]){
                u = dp[u][j]; ans += (1 << j);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}