这题一看 图论题 不会…… 那咋办呢 只能慢慢看 慢慢学
然后发现这题好像是使用了倍增数组的相关知识(这个还是有点熟的 学lca的时候弄了半天)
这题的关键就是那句 保证 v 在 u 前往首都的最短路径上 (v一定是u的祖先)
于是那个熟悉的方程就出来了 f[i][j]=f[f[i][j-1]][j-1]
这题具体实现如下(附备注)
输出方式还是坑了我一次(傻傻的输出的空格.....)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int const N = 2e5 + 5;
int n,q,val[N],m[N],ans;///val表示价值 m记录祖先
vector<int> g[N];///二维动态数组存边
int f[N][20], de[N];
/// f[i][j]表示 从i到目标点买了2^j次物品  所以有 f[i][j]=f[f[i][j-1]][j-1]
void dfs(int u, int p)///倍增常规操作
{
    de[u] = de[p] + 1;
    if (val[u] < val[p])
    {
        f[u][0] = p;
    }
    else
    {
        int x = p;
        for (int i = 19; i >= 0; --i)///x逼近第一个比val[u]大的结点下方的结点
        {
            if (f[x][i] && val[u] >= val[f[x][i]])
            {
                x = f[x][i];
            }
        }
        f[u][0] = f[x][0];///得到第一个比val[u]大的的祖先结点
    }
    for (int i = 1; i <= 19; ++i)///递推
    {
        f[u][i] = f[f[u][i-1]][i-1];
    }
    for (int i = 0; i < g[u].size(); ++i)
    {
        int v = g[u][i];
        if (v == p) continue;///到目标节点
        dfs(v, u);
    }
}
int main(){
    scanf("%d%d",&n,&q);
    for (int i = 1; i <= n; ++i) scanf("%d",&val[i]);
    for (int i = 0; i < n-1; ++i)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        g[u].push_back(v);///连边
        g[v].push_back(u);
    }
    for (int i = 1; i <= q; ++i)
    {
        int u,v,c;
        scanf("%d%d%d",&u,&v,&c);///题目保证了v是u的祖先
        g[n+i].push_back(u);///加点
        g[u].push_back(n+i);
        val[n+i] = c, m[i] = v;///新结点val设为c,记录目标祖先v
    }
    dfs(1, 0);
    for (int i = 1; i <= q; ++i)
    {
        int u,v;
        u = n+i, v = m[i],ans=0;
        for (int i = 19; i >= 0; --i)
        {
            if (de[f[u][i]] >= de[v])///u向v跳
            {
                u = f[u][i];
                ans += (1<<i);///买了2^i次
            }
        }
       printf("%d\n",ans);
    }
    return 0;
}