CF932F Escape Through Leaf
\(\text{Solution}\)
显然 \(dp\),\(f_x = min_{y\in subtree_x}f_y + a_x \cdot b_y\)
必然可以用李超线段树解决
在树上就线段树合并即可
当然可以树上启发式合并省去线段树合并,然后李超树维护
不过显然前者更好打
既然是斜率优化,还有一些平衡树或 \(CDQ\) 分治的做法,但看起来都比较麻烦
可这题挺模板的,直接上了李超线段树合并
\(\text{Code}\)
#include <cstdio>
#include <iostream>
#define re register
using namespace std;
typedef long long LL;
const int N = 1e5 + 5;
const LL INF = 1e18;
int a[N], b[N], h[N], Mn, Mx, tot, n;
LL f[N];
struct edge{int to, nxt;}e[N << 1];
inline void add(int x, int y){e[++tot] = (edge){y, h[x]}, h[x] = tot;}
inline void read(int &x)
{
x = 0; char ch = getchar(); int f = 1;
for(; !isdigit(ch); f = (ch == '-' ? -1 : f), ch = getchar());
for(; isdigit(ch); x = (x<<3) + (x<<1) + (ch^48), ch = getchar());
x *= f;
}
int ls[N << 5], rs[N << 5], flag[N << 5], size, rt[N];
struct line{LL k, b;}seg[N << 5];
inline LL calc(int p, int x){return seg[p].k * x + seg[p].b;}
inline double ISC(int p, LL k, LL b){return 1.0 * (b - seg[p].b) / (seg[p].k - k);}
void insert(int &p, int l, int r, LL k, LL b)
{
if (!p) p = ++size;
if (!flag[p]) return flag[p] = 1, seg[p] = (line){k, b}, void();
LL f1 = calc(p, l), f2 = calc(p, r), f3 = k * l + b, f4 = k * r + b;
if (f1 <= f3 && f2 <= f4) return;
if (f1 >= f3 && f2 >= f4) return void(seg[p] = (line){k, b});
if (l == r) return;
int mid = l + r >> 1; double len = ISC(p, k, b);
if (f1 >= f3)
{
if (len <= mid) insert(ls[p], l, mid, k, b);
else insert(rs[p], mid + 1, r, seg[p].k, seg[p].b), seg[p] = (line){k, b};
}
else{
if (len > mid) insert(rs[p], mid + 1, r, k, b);
else insert(ls[p], l, mid, seg[p].k , seg[p]. b), seg[p] = (line){k, b};
}
}
void merge(int &x, int y, int l, int r)
{
if (!x || !y) return void(x |= y);
insert(x, l, r, seg[y].k, seg[y].b);
if (l == r) return;
int mid = l + r >> 1;
merge(ls[x], ls[y], l, mid), merge(rs[x], rs[y], mid + 1, r);
}
LL Query(int p, int l, int r, int x)
{
if (!p || !flag[p]) return INF;
LL res = calc(p, x);
if (l == r) return res;
int mid = l + r >> 1;
if (x <= mid) return min(res, Query(ls[p], l, mid, x));
return min(res, Query(rs[p], mid + 1, r, x));
}
void dfs(int x, int fa)
{
for(re int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fa) continue;
dfs(v, x), merge(rt[x], rt[v], Mn, Mx);
}
if (rt[x]) f[x] = Query(rt[x], Mn, Mx, a[x]);
insert(rt[x], Mn, Mx, b[x], f[x]);
}
int main()
{
read(n), Mn = 1e5, Mx = -1e5;
for(re int i = 1; i <= n; i++) read(a[i]), Mn = min(Mn, a[i]), Mx = max(Mx, a[i]);
for(re int i = 1; i <= n; i++) read(b[i]), Mn = min(Mn, b[i]), Mx = max(Mx, b[i]);
for(re int i = 1, x, y; i < n; i++) read(x), read(y), add(x, y), add(y, x);
dfs(1, 0);
for(re int i = 1; i <= n; i++) printf("%lld ", f[i]);
}