题目链接
城市网络
题意:
做法:注意,题目中说明了v是u和v 的lca。
那么我们只需要树上倍增即可,f[i][j] 代表i节点往上走2^j的距离,且比当前大的点
因为是输入的权值,那么我就需要在所有需要问的点加一条新点,连在u的下方,新点的权值就是询问的初始权值,从这个新点往上倍增就可以了。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
vector<int>G[N];
int n,q;
int val[N],f[N][23],to[N],dep[N];
void dfs(int u,int fa)
{
dep[u] = dep[fa] + 1;
int x = fa;
for(int i = 22; i >= 0; --i){
if(f[x][i] && val[f[x][i]] <= val[u]) x = f[x][i];//找到第一个u节点小的点
}
if(val[x] > val[u]) f[u][0] = x;
else f[u][0] = f[x][0];
for(int i = 1; i <= 22; ++i) f[u][i] = f[f[u][i-1]][i-1];
for(int v:G[u]){
if(v == fa) continue;
dfs(v,u);
}
}
int main()
{
cin>>n>>q;
for(int i = 1; i <= n; ++i) scanf("%d",&val[i]);
for(int i = 1; i < n; ++i) {
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
for(int i = n + 1; i <= n + q ; ++i){//增加新点
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G[i].push_back(u);
G[u].push_back(i);
val[i] = w;
to[i - n] = v;
}
dfs(1,0);
//printf("f[6]:%d %d\n",f[6][1],f[f[6][0]][0]);
for(int i = 1; i <= q; ++i){
int x = i + n;
int ans = 0;
for(int k = 22; k >= 0; --k){
if(dep[f[x][k]] >= dep[to[i]]) {
//printf("x:%d k:%d f:%d\n",x,k,f[x][k]);
ans += (1 << k),x = f[x][k];
}
}
printf("%d\n",ans);
}
return 0;
}