zoukankan      html  css  js  c++  java
  • 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]);
    }
    
  • 相关阅读:
    sqlplus 登陆使用
    PLSQL设置显示的字符集及设置
    PL/SQL Developer使用技巧、快捷键
    微信小程序开发常见问题分析
    微信小程序如何使用PHP语言获取数据
    小程序获取网络类型代码
    微信小程序http转https
    小程序和Vue有哪些区别
    微信小程序时间标签与范围联动设计实现
    微信小程序http接口封装怎么实现
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/15563332.html
Copyright © 2011-2022 走看看