思路:
暴力的话复杂度很高,所以考虑倍增去找往上跳
f[i][j]表示i节点往上跳能买的第1<<j个节点的位置
跑一遍dfs处理出来所有点往上跳的可以购买的第j个位置在哪 然后每次询问复杂度只要logn即可
倍增应该先往大的跳,比如从1到5,应该从128,64,32,16,8,4,2,1 这样跳
这样的话1+4 直接到了5,相反如果从小的跳1+1+2<5 1+1+2+4=8>5 这样还需要往回跳处理较麻烦
#include <bits/stdc++.h> using namespace std; const int maxn=2e5+5; vector<int> e[maxn]; int a[maxn], f[maxn][20], dep[maxn], to[maxn]; void dfs(int p, int fa) { int x=fa; for(int k=19;k>=0;k--) if(f[x][k] && a[f[x][k]]<=a[p] ) x=f[x][k]; if(a[x]>a[p]) f[p][0]=x; else f[p][0]=f[x][0]; for(int i=1;i<20;i++)f[p][i]=f[f[p][i-1]][i-1]; dep[p]=dep[fa]+1; for(auto it:e[p]) if(it!=fa)dfs(it,p); } int main() { ios::sync_with_stdio(0); int n,q;cin>>n>>q; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<n;i++){ int x,y;cin>>x>>y; e[x].push_back(y); e[y].push_back(x); } for(int i=n+1;i<=n+q;i++){ int x,y,d;cin>>x>>y>>d; e[i].push_back(x); e[x].push_back(i); a[i]=d; to[i-n]=y; } dfs(1, 0); for(int i=1;i<=q;i++){ int ans=0; int x=i+n; for (int k=19;k>=0;k--) if(dep[f[x][k]]>=dep[to[i]]){ ans+=1<<k; x=f[x][k]; } cout<<ans<<endl; } return 0; }