题目描述

有一个树状的城市网络(即 n 个城市由 n-1 条道路连接的连通图),首都为 1 号城市,每个城市售卖价值为 a_i 的珠宝。
你是一个珠宝商,现在安排有 q 次行程,每次行程为从 u 号城市前往 v 号城市(走最短路径),保证 v 在 u 前往首都的最短路径上。 在每次行程开始时,你手上有价值为 c 的珠宝(每次行程可能不同),并且每经过一个城市时(包括 u 和 v ),假如那个城市中售卖的珠宝比你现在手上的每一种珠宝都要优秀(价值更高,即严格大于),那么你就会选择购入。
现在你想要对每一次行程,求出会进行多少次购买事件。


题解

注意题目里所说的‘**保证 v 在 u 前往首都的最短路径上’这就说明u,v,根,在一条链上。
那么我们就可以令dp[i][j]表示从i节点开始购入了2^j次所到达的点,转移方程为:
dp[i][j]=dp[dp[i][j-1]][j-1]。
在考虑怎么求dp[i][0]?
当i的父亲的珠宝>i的时dp[i][0]=fa,否则可以利用父亲的dp数组类似求lca那样得到dp[i][0].
考虑题中还有一个额外的C的限制,我们可以把c当作u的子节点,离线预处理即可。题目思路还是比较清晰的。注意几个细节吧

1.数组开两倍(新加了q个点
2.在求倍增求dp[i][0]时,要注意不能到达0节点,或者把0节点的价值设计为无穷


#include<bits/stdc++.h>
#define ls rt<<1
#define rs rt<<1|1
#define pb push_back
#define fi first
#define se second
#define ios ios::sync_with_stdio(0);
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef vector<int> VI;
const int maxn = 2e5 + 6;
const LL inf = 0x3f3f3f3f;
//const int mod = 998244353;
//LL qp(LL x,LL y){LL ans=1;x%=mod;while(y){if(y&1) ans=ans*x%mod;x=x*x%mod;y>>=1;}return ans;}

//head
int n,q,u[maxn],v[maxn],a[maxn],dp[maxn][50],dep[maxn];
VI G[maxn];

void dfs(int u,int fa){
    if(fa!=-1){
        if(a[u]<a[fa]) dp[u][0]=fa;
        else {
            int c=fa;
            for(int i=30;i>=0;i--){
                if(a[dp[c][i]]<a[u]&&dp[c][i]) {
                    c=dp[c][i];
                }
            }
            dp[u][0]=dp[c][0];
        }
        dep[u]=dep[fa]+1;
    }
    else dep[u]=1;

    for(int i=1;i<=30;i++){
        dp[u][i]=dp[dp[u][i-1]][i-1];
    }
    for(int i:G[u]){
        if(i==fa) continue;
        dfs(i,u);
    }
}

int main(){
    a[0]=inf;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1,u,v;i<n;i++){
        scanf("%d%d",&u,&v);
        G[u].pb(v);
        G[v].pb(u);
    }
    for(int i=1;i<=q;i++){
        scanf("%d%d%d",&u[i],&v[i],&a[i+n]);

        G[i+n].pb(u[i]);
        G[u[i]].pb(i+n);
        u[i]=i+n;
    }
    dfs(1,-1);
    for(int i=1;i<=q;i++){
        int ans=0;
        for(int j=30;j>=0;j--){
            if(dep[dp[u[i]][j]]>=dep[v[i]]){
                ans+=(1<<j);
                u[i]=dp[u[i]][j];
            }
        }
        printf("%d\n",ans);
    }
}