城市网络(倍增)

城市网络

https://ac.nowcoder.com/acm/problem/13331


题目:

有一个树状的城市网络(即 n 个城市由 n-1 条道路连接的连通图),首都为 1 号城市,每个城市售卖价值为 a_i 的珠宝。
你是一个珠宝商,现在安排有 q 次行程,每次行程为从 u 号城市前往 v 号城市(走最短路径),保证 v 在 u 前往首都的最短路径上。 在每次行程开始时,你手上有价值为 c 的珠宝(每次行程可能不同),并且每经过一个城市时(包括 u 和 v ),假如那个城市中售卖的珠宝比你现在手上的每一种珠宝都要优秀(价值更高,即严格大于),那么你就会选择购入。
现在你想要对每一次行程,求出会进行多少次购买事件。


做法:

下手慢了,数据更新了,暴力跑不动了。/(ㄒoㄒ)/~~









代码:

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define debug(a) cout << #a ": " << a << endl
using namespace std;
const int N = 2e5 + 7;
int n, q, val[N], mrk[N];
vector<int> g[N];
int fa[N][20], dep[N];
//fa[u][i]:保存u结点往根方向第2^i个val大于它的结点
void dfs(int u, int p){
    dep[u] = dep[p] + 1;//记录深度
    if (val[u] < val[p]){
        fa[u][0] = p;//若父节点p的val比u的val大,fa[u][0] = p
    }else{
        int x = p;
        for (int i = 19; i >= 0; --i){//x逼近第一个比val[u]大的结点下方的结点
            if (fa[x][i] && val[u] >= val[fa[x][i]]){
                x = fa[x][i];
            }
        }
        fa[u][0] = fa[x][0];//得到第一个比val[u]的的祖先结点
    }
    for (int i = 1; i <= 19; ++i){//倍增数组,递推
        fa[u][i] = fa[fa[u][i-1]][i-1];
    }
    for (int i = 0; i < g[u].size(); ++i){
        int v = g[u][i];
        if (v == p) continue;
        dfs(v, u);
    }
}
int main(void){
    IOS;
    cin >> n >> q;
    for (int i = 1; i <= n; ++i) cin >> val[i];
    for (int i = 0; i < n-1; ++i){
        int u, v; cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for (int i = 1; i <= q; ++i){
        int u, v, c; cin >> u >> v >> c;
        g[n+i].push_back(u);//每个询问新加一个结点连在u下面
        g[u].push_back(n+i);
        val[n+i] = c, mrk[i] = v;//新结点val设为c,记录目标祖先v
    }
    dfs(1, 0);//dfs预处理倍增数组
    for (int i = 1; i <= q; ++i){
        int u = n+i, v = mrk[i], ans = 0;
        for (int i = 19; i >= 0; --i){
            if (dep[fa[u][i]] >= dep[v]){//用倍增数组,从u往v跳
                u = fa[u][i];
                ans += (1<<i);//记录跳了多少步
            }
        }
        cout << ans << endl;
    }
    return 0;
}
全部评论
不懂,预处理倍增数组的时候不是要把所有的节点都遍历一遍吗,这样复杂度不还是很高吗
点赞 回复 分享
发布于 2021-01-21 17:30

相关推荐

03-26 13:04
已编辑
电子科技大学 算法工程师
xiaowl:你这个简历“条目上”都比较有深度性,但是实际上面试官又没法很好的评估你是怎么达到很多看上去很厉害的结果的。要避免一些看上去很厉害的包装,比如高效的内存复用策略的表达,如果仅是简单的一些内存共享机制,而且面试上也没有深挖的空间,就不要这样表达。比如,工程化模式本质上可能就是定义了一些abstract class,那也就没特别多值得讲的内容。建议简历上应该侧重那些你花了大量时间和精力解决、研究的问题,不要过分追求“丰富”,而是关注在技术深入度、问题解决能力的表现上。
没有实习经历,还有机会进...
点赞 评论 收藏
分享
03-03 23:12
已编辑
北京邮电大学 Java
书海为家:我来给一点点小建议,因为毕竟还在学校不像工作几年的老鸟有丰富的项目经验,面试官在面试在校生的时候更关注咱们同学的做事逻辑和思路,所以最好在简历中描述下自己做过项目的完整过程,比如需求怎么来的,你对需求的解读,你想到的解决办法,遇到困难如何找人求助,最终项目做成了什么程度,你从中收获了哪些技能,你有什么感悟。
你的简历改到第几版了
点赞 评论 收藏
分享
评论
10
3
分享

创作者周榜

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