码迷,mamicode.com
首页 > 其他好文 > 详细

CF932F(李超线段树+dp)

时间:2020-02-07 01:00:10      阅读:65      评论:0      收藏:0      [点我收藏+]

标签:code   def   char   dfs   const   上线   node   main   线段树   

CF932F(李超线段树+dp)

此题又是新玩法, 李超线段树合并优化\(dp\)

一个显然的\(\Theta(n^2)dp\): \(dp[x]\)表示从x出发到叶子节点的最小代价

\(dp[x] = \min(dp[y] + a[x] * b[y]) ~~(y \in subtree(x))\)

如果我们将\(b[y]\)看成斜率, \(dp[y]\)看成纵截距, \(a[x]\)看成横坐标, 那么问题转为了在平面上有一些直线, 选出与直线\(x = a[x]\)相交的最靠下的点吗, 李超线段树板题, 但这道题出到了树上所以要用上线段树合并 因为有负数所以要整体右移一下, 相应的直线也需变换, 具体见代码

代码:

#pragma GCC optimize(3)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define re register
#define ll long long
using namespace std;

template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
    for (;isdigit(c);c=getchar()) x=x*10+(c^48);
    if (f) x=-x;
}

template <typename T>
void write(T x) {
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

const int N = 200500;
const int Delta = 100005;
const int Len = Delta << 1;


int h[N], ne[N<<1], to[N<<1];
int T[N], tot, cnt;
inline void add(int x, int y) {
    ne[++tot] = h[x], to[tot] = y, h[x] = tot;
}

int ls[N<<5], rs[N<<5], p[N<<5];
ll n, ans[N], a[N], b[N];
struct node {
    ll k, b;
}line[N];

inline ll calc(int num, ll x) {
    return line[num].k * x + line[num].b;
}

void insert(int &x, int l, int r, int num) {
    if (!x) return x = ++cnt, p[x] = num, void();
    int mid = (l + r) >> 1;
    if (calc(p[x], mid) > calc(num, mid)) swap(p[x], num);
    if (calc(p[x], l) <= calc(num, l) && 
        calc(p[x], r) <= calc(num, r)) return;
    if (calc(p[x], l) > calc(num, l)) insert(ls[x], l, mid, num);
    else insert(rs[x], mid + 1, r, num);
}

const ll INF = 0x7fffffffffff;
ll query(int now, int l, int r, ll x) {
    if (!now) return INF;
    int mid = (l + r) >> 1;
    return min(calc(p[now], x), x <= mid ?
        query(ls[now], l, mid, x) : query(rs[now], mid + 1, r, x));
}

int merge(int x, int y, int l, int r) {
    if (!x || !y) return x | y;
    insert(x, l, r, p[y]);
    int mid = (l + r) >> 1;
    ls[x] = merge(ls[x], ls[y], l, mid);
    rs[x] = merge(rs[x], rs[y], mid + 1, r);
    return x;
}

void dfs(int x, int fa) {
    for (re int i = h[x], y; i; i = ne[i]) {
        if ((y = to[i]) == fa) continue;
        dfs(y, x); 
        T[x] = merge(T[x], T[y], 1, Len);
    }
    ans[x] = query(T[x], 1, Len, a[x] + Delta);
    if (ans[x] == INF) ans[x] = 0;
    line[x] = (node){b[x], ans[x] - b[x] * Delta}; 
    insert(T[x], 1, Len, x);
}

int main() {
    read(n);
    for (re int i = 1;i <= n; i++) read(a[i]);
    for (re int j = 1;j <= n; j++) read(b[j]);
    for (re int i = 1;i < n; i++) {
        int x, y; read(x), read(y);
        add(x, y), add(y, x);
    } dfs(1, 0);
    for (re int i = 1;i <= n; i++) 
        write(ans[i]), putchar(' ');
    return 0;
}

CF932F(李超线段树+dp)

标签:code   def   char   dfs   const   上线   node   main   线段树   

原文地址:https://www.cnblogs.com/Hs-black/p/12271622.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!