解题思路
g
i
,
j
g_{i,j}
gi,j表示从 i 节点往上购买
2
j
2^j
2j 次到达的节点,如果我们知道了
g
i
,
0
g_{i,0}
gi,0就可以求出所有了(倍增的精髓)
g
i
,
0
g_{i,0}
gi,0 就是求 i 节点从下往上第一个大于
a
i
a_i
ai 的节点,这也可以用倍增来完成,用一个
m
a
x
n
i
,
j
maxn_{i,j}
maxni,j来维护从 i 节点往上
2
j
2^j
2j步这中的最大值,若
m
a
x
n
i
,
j
<
a
i
maxn_{i,j}<a_i
maxni,j<ai,则
i
=
f
i
,
j
i=f_{i,j}
i=fi,j,i 一直往上跳。最后第一个大于
a
i
a_i
ai 的节点为
f
i
,
0
f_{i,0}
fi,0
最后计算答案的时候,若 c > a u c>a_u c>au,要先找到以一个大于c的节点 u , a n s + + u,ans++ u,ans++,再从那里开始往上跳,枚举j,即枚举往上购买 2 j 2^j 2j 次,若 g u , j g_{u,j} gu,j 没有超过 v , a n s + = 2 j v,ans+=2^j v,ans+=2j
代码
#include <bits/stdc++.h>
#define ll long long
#define N 100010
using namespace std;
int n,q,u,v,s,k,ans;
int head[N*2],w[N],f[N][25],g[N][25],dep[N],maxn[N][25],lg[N];
struct c {
int x,next;
} a[N*2];
void add(int x,int y) {
a[++k]=(c) {
y,head[x]};
head[x]=k;
}
void dfs(int x,int fa) {
dep[x]=dep[fa]+1;
f[x][0]=fa;
maxn[x][0]=max(w[x],w[fa]);
for(int i=1; i<=20; i++) {
f[x][i]=f[f[x][i-1]][i-1];
maxn[x][i]=max(maxn[x][i-1],maxn[f[x][i-1]][i-1]);
}
int xx=x;
for(int i=20; i>=0; i--) {
if(maxn[xx][i]<=w[x])
xx=f[xx][i];
}
g[x][0]=f[xx][0];
for(int i=1; i<=20; i++)
g[x][i]=g[g[x][i-1]][i-1];
for(int i=head[x]; i; i=a[i].next) {
int y=a[i].x;
if(y==fa)continue;
dfs(y,x);
}
}
int main() {
freopen("network.in","r",stdin);
freopen("network.out","w",stdout);
scanf("%d%d",&n,&q);
lg[0]=-1;
for(int i=1; i<=n; i++)
lg[i]=lg[i>>1]+1;
for(int i=1; i<=n; i++)
scanf("%d",&w[i]);
for(int i=1; i<=n-1; i++) {
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,0);
for(int i=1; i<=q; i++) {
scanf("%d%d%d",&u,&v,&s);
ans=1;
if(w[u]<=s)
{
for(int j=20;j>=0;j--)
{
if(maxn[u][j]<=s)
u=f[u][j];
}
u=f[u][0];
}
if(!u||dep[u]<dep[v]){
printf("0\n");
continue;
}
for(int j=20; j>=0; j--) {
if(g[u][j]&&dep[g[u][j]]>=dep[v])
{
u=g[u][j];
ans=ans+pow(2,j);
}
}
printf("%d\n",ans);
}
}