CF932F Escape Through Leaf

首先, $ O(n^2) $ dp 是很显然的,方程长这样:

\[dp[u] = min\{dp[v] + a_u\times b_v\}
\]

这个方程看起来就很斜率,当我们写成了斜率优化的形式大概是这样的:

\[\frac{dp[v]-dp[j]}{a_v-a_j} < -b_u
\]

我们想通过这个式子做就必须维护动态凸包以及凸包的合并。这个东西是很恼火的,可能用 set 和 splay 啥的可以搞,可惜不大会。

这里就引入了一种科技,李超线段树

李超线段树是一种维护线段的线段树,支持插入一个线段,询问 $ x_0 $ 上的最大/最小值。

不难发现这个 dp 方程就是个直线的形式,当我们计算完了 $ u $ 就把 $ b_ux+dp[u] $ 这个直线插入。查询就是查 $ a_u$ 的值。

李超树的实现是每个点存储一个直线,考虑我们插入一个线段到一个节点:

  • 这里没有线段,直接放进去
  • 这里有线段但是被这个线段完爆,把这个位置的线段替换掉 return
  • 这里有线段并且完爆插入线段,直接return
  • 否则,必然插入线段和节点线段有交,把较长一段放在这里,较短的递归到一个子树。因为较短的必然不超过节点长度的一半。

这题还需要写一个线段树合并,和普通的线段树合并也没啥区别,就是先递归合并,最后把需要合并进去的树的当前节点的线段插入当前树的这个节点。

最终复杂度,看起来很 $ O(n\log^2n) $ 但是有神仙证明了复杂度是 $ O(n\log n) $ 也不是很清楚了。

这个东西还是很好写的:

#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "vector"
using namespace std;
#define MAXN 100006
typedef long long ll;
#define min( a , b ) ( (a) < (b) ? (a) : (b) )
int n , m , L;
#define D 100006
int A[MAXN] , B[MAXN];
vector<int> G[MAXN]; struct line {
ll k , b;
ll re( ll x ) { return k * x + b; }
} f[MAXN] ; int ls[MAXN << 4] , rs[MAXN << 4] , id[MAXN << 4] , cnt , rt[MAXN];
void ins( int& x , int l , int r , int d ) {
if( !x ) { x = ++ cnt , id[x] = d; return; }
int m = l + r >> 1;
if( f[id[x]].re( m ) > f[d].re( m ) ) swap( d , id[x] );
if( f[id[x]].re( l ) <= f[d].re( l ) && f[id[x]].re( r ) <= f[d].re( r ) ) return;
if( f[id[x]].re( l ) > f[d].re( l ) ) ins( ls[x] , l , m , d );
else ins( rs[x] , m + 1 , r , d );
}
long long que( int x , int l , int r , int p ) {
if( !x ) return 0x3f3f3f3f3f3f3f3f;
int m = l + r >> 1; ll re = f[id[x]].re( p );
if( p <= m ) return min( re , que( ls[x] , l , m , p ));
else return min( re , que( rs[x] , m + 1 , r , p ));
}
int merge( int x , int y , int l , int r ) {
// printf("%d %d %d %d\n",x,y,l,r);
if( !x || !y ) return x + y;
ins( x , l , r , id[y] );
int m = l + r >> 1;
ls[x] = merge( ls[x] , ls[y] , l , m );
rs[x] = merge( rs[x] , rs[y] , m + 1 , r );
return x;
}
long long ans[MAXN];
void dfs( int u , int fa ) {
for( int v : G[u] ) if( v != fa ) {
dfs( v , u );
rt[u] = merge( rt[u] , rt[v] , 1 , D << 1 );
}
ans[u] = que( rt[u] , 1 , D << 1 , A[u] + D );
if( ans[u] > 1e18 ) ans[u] = 0;
f[u] = (line) { B[u] , ans[u] - 1ll * B[u] * D };
ins( rt[u] , 1 , D << 1 , u );
}
int main() {
cin >> 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 , 1 );
for( int i = 1 ; i <= n ; ++ i ) printf("%lld ",ans[i]);
}

CF932F Escape Through Leaf的更多相关文章

  1. CF932F Escape Through Leaf 斜率优化、启发式合并

    传送门 \(DP\) 设\(f_i\)表示第\(i\)个节点的答案,\(S_i\)表示\(i\)的子节点集合,那么转移方程为\(f_i = \min\limits_{j \in S_i} \{a_i ...

  2. CF932F Escape Through Leaf(DP,斜率优化)

    SB 题. 写出 DP 方程:\(f_i\) 表示从 \(i\) 跳的最小值. \(i\) 是叶子就是 \(0\),否则就是选个子树中的 \(v\),\(f_i=\min(f_v+a_ib_v)\). ...

  3. 【CF932F】Escape Through Leaf 启发式合并set维护凸包

    [CF932F]Escape Through Leaf 题意:给你一棵n个点的树,每个点有树形ai和bi,如果x是y的祖先,则你可以从x花费$a_x\times b_y$的费用走到y(费用可以为负). ...

  4. Codeforces 932.F Escape Through Leaf

    F. Escape Through Leaf time limit per test 3 seconds memory limit per test 256 megabytes input stand ...

  5. 932F Escape Through Leaf

    传送门 题目大意 https://www.luogu.org/problemnew/show/CF932F 分析 我们可以从叶子向根每次插入b和ans 所以我们不难发现就是相当于插入线段 于是李超树+ ...

  6. Codeforces Round #463 F. Escape Through Leaf (李超线段树合并)

    听说正解是啥 set启发式合并+维护凸包+二分 根本不会啊 , 只会 李超线段树合并 啦 ... 题意 给你一颗有 \(n\) 个点的树 , 每个节点有两个权值 \(a_i, b_i\) . 从 \( ...

  7. 【CF 463F】Escape Through Leaf

    题意 给你一棵 \(n\) 个点的树,每个节点有两个权值 \(a_i,b_i\). 从一个点 \(u\) 可以跳到以其为根的子树内的任意一点 \(v\)(不能跳到 \(u\) 自己),代价是 \(a_ ...

  8. @codeforces - 932F@ Escape Through Leaf

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个 n 个点的树(标号1~n),以结点 1 为根.每个结点 ...

  9. Codeforces Round #463

    A - Palindromic Supersequence /* 题目大意:给出一个串,构造一个包含该串的回文串 */ #include <cstdio> #include <alg ...

随机推荐

  1. 【java】关键字this怎么用?

    摘至:https://www.php.cn/java/guide/462643.html java中this关键字的用法:1.当成员变量和局部变量重名时,在方法中使用this时,表示的是该方法所在类中 ...

  2. dubbo注册中心占位符无法解析问题(二)

    dubbo注册中心占位符无法解析问题 前面分析了dubbo注册中心占位符无法解析的问题. 并给出了2种解决办法: 降低mybatis-spring的版本至2.0.1及以下 自定义MapperScann ...

  3. 设置elementUI的table组件滚动条位置

    1.设置table的ref为tableList 2.设置滚动至顶部 this.$refs.tableList.bodyWrapper.scrollTop =0; 3.设置滚动至底部 this.$ref ...

  4. 3.4 Common Principles 通用原则

    3.4 Common Principles 通用原则 Before going into details, let's see some overall DDD principles; 在讨论细节之前 ...

  5. Java内存分析--栈--堆

    Java内存分析--栈--堆 JVM的内存分析: 1.栈内存 1.连续的存储空间,遵循后进先出的原则. 2.每个线程包含一个栈区,栈区只保存基础数据类型的对象和自定义对象的引用. 3.每个栈中的数据都 ...

  6. 保护模式篇——TLB与CPU缓存

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  7. Less-23 preg_replace1

    Less-23: 直接跳到Less-23的原因是,Less-(11~22)均为注入点不为get方式的注入.我先把get型注入写的差不多,再回来整理关于注入点的内容. 核心语句: 查询.报错均有回显. ...

  8. Java:NIO 学习笔记-2

    Java:NIO 学习笔记-2 上一篇 NIO 学习笔记-1 看了 尚硅谷 的相应教程,此处又对比看了 黑马程序员 的课程 JAVA通信架构I/O模式,做了相应的笔记 前言 在 Java 的软件设计开 ...

  9. js基础学习之"=="与"==="的区别

    var a = 1; var b = 1; var c = "1"; 1. "==" 可理解为相等运算符.相等运算符比较时,会自己进行类型转换,等于什么类型就会 ...

  10. VirtualBox问题解决合集 - [drm:vmw_host_log [vmwgfx]] *ERROR* Failed to send host log message

    转载:https://blog.csdn.net/mychangee/article/details/104954262 问题描述:[drm:vmw_host_log [vmwgfx]] ERROR  ...