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;
}
浙公网安备 33010602011771号