我们考虑一个暴力的做法:每次从这个点找到它上面的第一个比他大的点 跳过去。
但是这样显然是过不了的。我们先丢掉询问给出的那个权 每次就拿这个点上的权来跳 答案如何快速处理。
我们可以倍增:
往上找了
个答案之后的点在哪里。问题转化为处理
这个也可以利用我们前面已经求出的f来计算:观察到 随着
的递增而递增。所以我们可以用类似询问倍增的方式来做:每次枚举
比较
和当前点的权 决定跳不跳。
对于询问 题解里有一个很巧妙的做法:将每个点接在起点的下面就可以了(也可以每一次都先倍增找到第一个比它大的)
#include<bits/stdc++.h>
#define fi first
#define se second
#define U unsigned
#define P std::pair<int,int>
#define LL long long
#define pb push_back
#define MP std::make_pair
#define all(x) x.begin(),x.end()
#define CLR(i,a) memset(i,a,sizeof(i))
#define FOR(i,a,b) for(int i = a;i <= b;++i)
#define ROF(i,a,b) for(int i = a;i >= b;--i)
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl
const int MAXN = 5e5 + 5;
struct Edge{
int to,nxt;
}e[MAXN<<1];
int head[MAXN],cnt;
inline void add(int u,int v){
e[++cnt] = (Edge){v,head[u]};head[u] = cnt;
e[++cnt] = (Edge){u,head[v]};head[v] = cnt;
}
int n;
int a[MAXN];
int b[MAXN],dep[MAXN],f[MAXN][20];
inline void dfs(int v,int fa=0){
int t = fa;
ROF(i,19,0){
if(f[t][i] && a[f[t][i]] <= a[v]) t = f[t][i];
}
if(a[t] > a[v]) f[v][0] = t;
else f[v][0] = f[t][0];
FOR(i,1,19) f[v][i] = f[f[v][i-1]][i-1];
for(int i = head[v];i;i = e[i].nxt){
if(e[i].to == fa) continue;
dep[e[i].to] = dep[v] + 1;dfs(e[i].to,v);
}
}
int main(){
int q;scanf("%d%d",&n,&q);
FOR(i,1,n) scanf("%d",a+i);
FOR(i,2,n){
int u,v;scanf("%d%d",&u,&v);add(u,v);
}
FOR(i,n+1,n+q){
int u,v,w;scanf("%d%d%d",&u,&v,&w);
add(i,u);
a[i] = w;b[i-n] = v;
}
dep[1] = 1;dfs(1,0);
FOR(i,1,q){
int ans = 0,v = i+n;
ROF(k,19,0){
if(dep[f[v][k]] >= dep[b[i]]){
ans |= (1<<k);
v = f[v][k];
}
}
printf("%d\n",ans);
}
return 0;
}

京公网安备 11010502036488号