题意

给定一棵树,有 个点,根节点为 ,每个节点有一个值
个询问,每个询问包含 ,问当前值为 ,从 走到 ,每次遇到比当前值大的值,即将当前值替换为该值,最终总共要替换多少次。( 到根节点的路径上)

分析

这题还是很有必要记录一下的!
首先我们每次可以在 后面接一个点 点的值为 ,相当于每次从 走向
然后暴力是 ,显然不可取。
但是如果我们能快速知道每个值往上走第一个比它大的值,就可以倍增来解决了。
问题是,怎么获取每个值往上走的第一个比它大的值呢?
注意到,比 大的第一个值,一定是 或这比 大的第 个值( 为正整数,这里假设 的值为无穷大)。
于是,我们可以用倍增来求比 大的第一个点。
就是每次从父节点往上跑,如果某一段都比 小,那么答案肯定不在这一段里,否则答案肯定在这一段里。
有点二分的感觉。
处理完 表,回答询问就很简单了。就是深度满足就往上爬。
总复杂度

代码如下

#include <bits/stdc++.h>
#define N 300005
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
LL z = 1;
struct node{
    int a, b, n;
}d[N * 2];
int h[N], fa[N], w[N], q[N][2], st[N][20], dep[N], cnt;
void cr(int a, int b){
    d[++cnt].a = a; d[cnt].b = b; d[cnt].n = h[a]; h[a] = cnt;
}
int read(){
    int x, f = 1;
    char ch;
    while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1;
    x = ch - '0';
    while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48;
    return x * f;
}
void dfs(int a){
    int i, b, t;
    if(w[a] < w[fa[a]]) st[a][0] = fa[a];
    else{
        t = fa[a];
        for(i = 19; i >= 0; i--){
            if(st[t][i] && w[st[t][i]] <= w[a]) t = st[t][i];
        }
        st[a][0] = st[t][0];
    }
    for(i = 1; i <= 19; i++) st[a][i] = st[st[a][i - 1]][i - 1];
    for(i = h[a]; i; i = d[i].n){
        b = d[i].b;
        if(b == fa[a]) continue;
        fa[b] = a;
        dep[b] = dep[a] + 1;
        dfs(b);
    }
}
int main(){
    int i, j, n, m, a, b, ans = 0;
    n = read(); m = read();
    for(i = 1; i <= n; i++) w[i] = read();
    for(i = 1; i < n; i++){
        a = read(); b = read();
        cr(a, b);
        cr(b, a);
    }
    for(i = 1; i <= m; i++){
        q[i][0] = read(); q[i][1] = read(); w[i + n] = read();
        cr(i + n, q[i][0]);
        cr(q[i][0], i + n);
    }
    dep[1] = 1;
    dfs(1);
    for(i = 1; i <= m; i++){
        ans = 0;
        a = i + n, b = q[i][1];
        for(j = 19; j >= 0; j--){
            if(dep[st[a][j]] >= dep[b]){
                a = st[a][j];
                ans += (1 << j);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}