思路:
暴力的话复杂度很高,所以考虑倍增去找往上跳
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;
}

京公网安备 11010502036488号