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]);
}
原文地址:https://www.cnblogs.com/leiyuanze/p/15563332.html