CF932F. Escape Through Leaf 题解 李超线段树合并 + DP

题目链接:https://codeforces.com/problemset/problem/932/F

前置知识:

  • 李超线段树 + 李超线段树合并,见 oi.wiki

本题解题思路:

  • 在掌握前置知识后,其实你会发现这是一道模板题。但是也可以参考一下官方的题解。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5, maxm = maxn * 20, M = 1e5;

struct Line {
    int k;
    long long b; // y=kx+b
} line[maxn];
int idx, idx2, rub[maxm], ls[maxm], tr[maxm], rs[maxm], rt[maxm];
long long f[maxn];
int n, a[maxn], b[maxn];
vector<int> g[maxn];

int New() {
    return idx2 ? rub[idx2--] : ++idx;
}

void Del(int &u) {
    ls[u] = rs[u] = tr[u] = 0;
    rub[++idx2] = u;
    u = 0;
}

long long get_y(int p, int x) {
    auto [k, b] = line[p];
    return 1ll * k * x + b;
}

int cmp(long long a, long long b) {
    if (a > b) return 1;
    if (a < b) return -1;
    return 0;
}

// 增加第 p 条线段
void upd(int p, int l, int r, int &u) {
    if (!u) {
        u = New();
        tr[u] = p;
        return;
    }
    int mid = l + r >> 1;
    int &q = tr[u], c_mid = cmp(get_y(p, mid), get_y(q, mid));
    if (c_mid == -1) swap(p, q);
    if (l == r) return;
    int c_l = cmp(get_y(p, l), get_y(q, l)), c_r = cmp(get_y(p, r), get_y(q, r));
    if (c_l == -1) upd(p, l, mid, ls[u]);
    if (c_r == -1) upd(p, mid+1, r, rs[u]);
}

int Merge(int l, int r, int a, int b) {
    if (!a || !b) return a + b;
    if (l == r) {
        if (!tr[a] || !tr[b])
            tr[a] += tr[b];
        else if (cmp(get_y(tr[a], l), get_y(tr[b], l)) == 1)
            swap(a, b);
        Del(b);
        return a;
    }
    int mid = l + r >> 1;
    upd(tr[b], l, r, a);
    ls[a] = Merge(l, mid, ls[a], ls[b]);
    rs[a] = Merge(mid+1, r, rs[a], rs[b]);
    Del(b);
    return a;
}

long long query(int x, int l, int r, int u) {
    long long res = 1e15;
    if (!u || !tr[u])
        return res;
    if (tr[u]) res = min(res, get_y(tr[u], x));
    if (l < r) {
        int mid = l + r >> 1;
        long long tmp = (x <= mid) ? query(x, l, mid, ls[u]) : query(x, mid+1, r, rs[u]);
        res = min(res, tmp);
    }
    return res;
}

void dfs(int u, int p) {
    if (u != 1 && g[u].size() == 1) { // 叶子节点
        f[u] = 0;
    }
    else {
        for (auto v : g[u]) {
            if (v != p) {
                dfs(v, u);
                rt[u] = Merge(-M, M, rt[u], rt[v]);
            }
        }
        f[u] = query(a[u], -M, M, rt[u]);
    }
    line[u] = { b[u], f[u] };
    upd(u, -M, M, rt[u]);
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", a+i);
    for (int i = 1; i <= n; i++) scanf("%d", b+i);
    for (int i = 1, u, v; i < n; i++) {
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1, 0);
    for (int i = 1; i <= n; i++)
        printf("%lld ", f[i]);
    return 0;
}
posted @ 2026-03-19 20:40  quanjun  阅读(1)  评论(0)    收藏  举报