牛客 城市网络 树上倍增

牛客 城市网络

题意

给一棵 n n n 个点的树,每个节点代表一个城市,每个城市卖价值为 a i a_i ai 的珠宝,有 q q q 次询问,每次询问从 u u u 城市到 v v v 城市,一开始有价值为 c c c 的珠宝,如果当前经过的城市珠宝价值大于已有的所有珠宝的最大价值,就购买。保证 v v v u u u 到根的路径上。问这次行程有几次购买。

题解

  • 一次次的跳转到自己的父亲显然时间复杂度过大,所以考虑倍增跳转;

  • 对于每次询问,在 u u u 的下方连一个虚拟的城市,城市卖价值为 c c c 的珠宝;

  • f [ u ] [ i ] f[u][i] f[u][i] 表示编号为 u u u 的城市出发第 2 i 2^i 2i 次购买在哪个城市;

  • i i i 1 1 1 开始可以使用类似求lca的方法进行转移,那么需要找到 f [ u ] [ 0 ] f[u][0] f[u][0]

  • f [ u ] [ 0 ] f[u][0] f[u][0] 也是倍增跳转, a [ f [ u ] [ i ] ] a[f[u][i]] a[f[u][i]] 是关于 i i i 递增的, x x x u u u 的父亲城市, i i i 从大到小枚举,如果 a [ f [ x ] [ i ] ] < a [ u ] a[f[x][i]]<a[u] a[f[x][i]]<a[u] ,说明需要跳转的位置还在上面,先转移再继续循环判断;

  • 询问的时候根据深度来判断即可,倍增跳转即可。

代码

#pragma region
//#pragma optimize("Ofast")
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
#define tr t[root]
#define lson t[root << 1]
#define rson t[root << 1 | 1]
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
#pragma endregion
const int maxn = 2e5 + 5;
int n, q;
vector<int> g[maxn];
int a[maxn], to[maxn];
int fa[maxn][20], dep[maxn];
void dfs(int u, int f) {
    
    
    dep[u] = dep[f] + 1;
    int x = f;
    for (int i = 19; i >= 0; --i) {
    
    
        if (!fa[x][i]) continue;
        if (a[fa[x][i]] <= a[u]) x = fa[x][i];
    }
    fa[u][0] = (a[x] > a[u] ? x : fa[x][0]);
    for (int i = 1; (1 << i) <= dep[u]; ++i)
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    for (auto v : g[u]) {
    
    
        if (v == f) continue;
        dfs(v, u);
    }
}
int query(int id) {
    
    
    int ans = 0, x = id + n;
    for (int i = 19; i >= 0; --i) {
    
    
        if (dep[fa[x][i]] >= dep[to[id]]) {
    
    
            ans += (1 << i);
            x = fa[x][i];
        }
    }
    return ans;
}
int main() {
    
    
    scanf("%d%d", &n, &q);
    rep(i, 1, n) scanf("%d", &a[i]);
    rep(i, 1, n - 1) {
    
    
        int u, v;
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    rep(i, n + 1, n + q) {
    
    
        int u, v, c;
        scanf("%d%d%d", &u, &v, &c);
        g[i].push_back(u);
        g[u].push_back(i);
        a[i] = c;
        to[i - n] = v;
    }
    dfs(1, 0);
    rep(i, 1, q) printf("%d\n", query(i));
}

猜你喜欢

转载自blog.csdn.net/weixin_43860866/article/details/112746553