传送门
题解:
题目中保证了u到v一定在最短路径上,所以考虑用树上倍增的方法。我们fa数组存的是比当前节点val值严格大的最近祖先。然后每次倍增的时候更新答案就可以了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+7;
int head[N],e[N<<1],ne[N<<1],fa[N][25],val[N],cnt,pre[N],dep[N];
void add(int a,int b)
{
e[cnt]=b,ne[cnt]=head[a],head[a]=cnt++;
}
void dfs(int u,int f)
{
dep[u]=dep[f]+1;
if(val[u]<val[f]){
fa[u][0]=f;
} else{
int x=f;
for(int i=20;i>=0;i--){
if(fa[x][i]&&val[u]>=val[fa[x][i]]){
x=fa[x][i];
}
}
fa[u][0]=fa[x][0];
}
for(int i=1;i<=20;i++){
fa[u][i]=fa[fa[u][i-1]][i-1];
}
for(int i=head[u];~i;i=ne[i]){
int j=e[i];
if(f==j) continue;
dfs(j,u);
}
}
int main()
{
memset(head,-1,sizeof head);
int n,q; scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",val+i);
for(int i=1;i<n;i++) {
int a,b;
scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
for(int i=1;i<=q;i++){
int u,v,c; scanf("%d%d%d",&u,&v,&c);
add(i+n,u),add(u,i+n);
val[i+n]=c,pre[i]=v;
}
dfs(1,0);
for(int i=1;i<=q;i++){
int u=i+n,v=pre[i],res=0;
for(int j=20;j>=0;j--){
if(dep[v]<=dep[fa[u][j]]){
u=fa[u][j];
res+=1<<j;
}
}
printf("%lld\n",res);
}
}