【每日一题】3月31日题目精讲 树上倍增

题目链接

城市网络

题意:

做法:注意,题目中说明了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;

}
发布了519 篇原创文章 · 获赞 69 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/105221228
今日推荐