NC13331 城市网络

城市网络

https://ac.nowcoder.com/acm/contest/8/A

题意

给定一棵树,有 个点,根节点为 ,每个节点有一个值
个询问,每个询问包含 ,问当前值为 ,从 走到 ,每次遇到比当前值大的值,即将当前值替换为该值,最终总共要替换多少次。( 到根节点的路径上)

分析

这题还是很有必要记录一下的!
首先我们每次可以在 后面接一个点 点的值为 ,相当于每次从 走向
然后暴力是 ,显然不可取。
但是如果我们能快速知道每个值往上走第一个比它大的值,就可以倍增来解决了。
问题是,怎么获取每个值往上走的第一个比它大的值呢?
注意到,比 大的第一个值,一定是 或这比 大的第 个值( 为正整数,这里假设 的值为无穷大)。
于是,我们可以用倍增来求比 大的第一个点。
就是每次从父节点往上跑,如果某一段都比 小,那么答案肯定不在这一段里,否则答案肯定在这一段里。
有点二分的感觉。
处理完 表,回答询问就很简单了。就是深度满足就往上爬。
总复杂度

代码如下

#include <bits/stdc++.h>
#define N 300005
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
LL z = 1;
struct node{
    int a, b, n;
}d[N * 2];
int h[N], fa[N], w[N], q[N][2], st[N][20], dep[N], cnt;
void cr(int a, int b){
    d[++cnt].a = a; d[cnt].b = b; d[cnt].n = h[a]; h[a] = cnt;
}
int read(){
    int x, f = 1;
    char ch;
    while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1;
    x = ch - '0';
    while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48;
    return x * f;
}
void dfs(int a){
    int i, b, t;
    if(w[a] < w[fa[a]]) st[a][0] = fa[a];
    else{
        t = fa[a];
        for(i = 19; i >= 0; i--){
            if(st[t][i] && w[st[t][i]] <= w[a]) t = st[t][i];
        }
        st[a][0] = st[t][0];
    }
    for(i = 1; i <= 19; i++) st[a][i] = st[st[a][i - 1]][i - 1];
    for(i = h[a]; i; i = d[i].n){
        b = d[i].b;
        if(b == fa[a]) continue;
        fa[b] = a;
        dep[b] = dep[a] + 1;
        dfs(b);
    }
}
int main(){
    int i, j, n, m, a, b, ans = 0;
    n = read(); m = read();
    for(i = 1; i <= n; i++) w[i] = read();
    for(i = 1; i < n; i++){
        a = read(); b = read();
        cr(a, b);
        cr(b, a);
    }
    for(i = 1; i <= m; i++){
        q[i][0] = read(); q[i][1] = read(); w[i + n] = read();
        cr(i + n, q[i][0]);
        cr(q[i][0], i + n);
    }
    dep[1] = 1;
    dfs(1);
    for(i = 1; i <= m; i++){
        ans = 0;
        a = i + n, b = q[i][1];
        for(j = 19; j >= 0; j--){
            if(dep[st[a][j]] >= dep[b]){
                a = st[a][j];
                ans += (1 << j);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
每日一题 文章被收录于专栏

牛客的每日一题(换卫衣之路(bushi

全部评论
请问一下倍增中为什么i要倒着遍历
点赞 回复 分享
发布于 2020-05-03 22:10

相关推荐

求个付费实习岗位:这种就是吃满时代红利又没啥技术水平,只能靠压力学生彰显优越感的老登,别太在意了
点赞 评论 收藏
分享
程序员花海:实习和校招简历正确格式应该是教育背景+实习+项目经历+个人评价 其中项目经历注意要体现业务 实习经历里面的业务更是要自圆其说 简历模板尽可能保持干净整洁 不要太花哨的
秋招吐槽大会
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务