Codeforces Round #463 F. Escape Through Leaf (李超线段树合并)
听说正解是啥 set启发式合并+维护凸包+二分 根本不会啊 , 只会 李超线段树合并 啦 ...
题意
给你一颗有 \(n\) 个点的树 , 每个节点有两个权值 \(a_i, b_i\) .
从 \(u\) 跳到 \(v\) 的代价是 \(a_u \times b_v\) . 你需要计算每个节点跳到叶子的最小代价 .
\((n \le 10^5, -10^5 \le a_i, b_i \le 10^5)\)
题解
我们首先考虑一个很容易的 \(dp\) , 令 \(dp_i\) 为 \(i\) 跳到叶子的最小代价 .
那么显然有一个转移 此处 \(v\) 是 \(u\) 的后代 .
\]
暴力转移是 \(O(n^2)\) 的显然无法接受 .
那么考虑优化 , 不难发现这个转移就是 李超线段树上求多条直线 \(y=kx+b\) 在 \(x=k\) 最值的形式 .
\((k = b[v], x = a[u], b=dp_v)\)
那么显然可以考虑用李超线段树维护这个 \(dp\) .
对于树上的每个点 , 可以用一颗李超线段树维护这个点子树的所有直线信息 .
然后我们只需要考虑合并几颗子树信息了 , 不难发现是 套路的 线段树合并 . (这样时间空间复杂度都正确了?)
我们直接同时遍历两颗线段树 , 然后把其中一颗当前区间的优势直线暴力插入另外一颗线段树 .
最后把子树全都合并上来后 , 直接询问出 \(dp_u\) 就行了 , 然后再插入到这颗线段树中去 .
由于询问 \(a_i\) 可能为负数 , 而线段树不太好维护负数 , 我们考虑插入直线和询问的时候都向右平移 \(lim = 10^5\) 长度 .
原来的直线 \(y=kx+b\) 就变成了 \(y'=k(x-lim)+b=kx+(b-k\cdot lim)\) 了 .
(也许可以维护负数 diversion 说可以)
最后瞎分析时间复杂度 \(O(\sum minsize \log n) = O(n \log ^2 n)\) ... (错了的话大佬帮我指正啊qwq)
这道题还是比较好写的 ...
代码
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define debug(x) cout << #x << ':' << x << endl
using namespace std;
inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * fh;
}
void File() {
#ifdef zjp_shadow
freopen ("F.in", "r", stdin);
freopen ("F.out", "w", stdout);
#endif
}
const int N = 2e5 + 1e3, Lim = 1e5 + 5;
typedef long long ll;
struct Line { ll k, b; int id; ll func(int x) { return k * x + b; } };
inline bool Cmp(Line a, Line b, int x) { if (!a.id) return true; return a.func(x) > b.func(x); }
int rt[N];
const int Maxn = N * 30;
#define lson ls[o], l, mid
#define rson rs[o], mid + 1, r
struct Chao_Segment_Tree {
Line Adv[Maxn]; int ls[Maxn], rs[Maxn], Size;
Chao_Segment_Tree () {Size = 0;};
void Insert(int &o, int l, int r, Line uv) {
if (!o) o = ++ Size;
int mid = (l + r) >> 1;
if (Cmp(Adv[o], uv, mid)) swap(Adv[o], uv);
if (l == r || Adv[o].k == uv.k || !uv.id) return ;
double x = (double)(Adv[o].b - uv.b) / (uv.k - Adv[o].k);
if (x < l || x > r) return ;
if (uv.k > Adv[o].k) Insert(lson, uv); else Insert(rson, uv);
}
int Merge(int x, int y, int l, int r) {
if (!x || !y) return x + y;
Insert(x, l, r, Adv[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;
}
Line Query(int o, int l, int r, int qp) {
if (l == r) return Adv[o];
int mid = (l + r) >> 1;
Line tmp = (qp <= mid) ? Query(lson, qp) : Query(rson, qp);
return Cmp(tmp, Adv[o], qp) ? Adv[o] : tmp;
}
} T;
int n, A[N], B[N]; vector<int> G[N];
ll dp[N];
inline void Insert(int ver) {
ll k = B[ver], b = dp[ver] - Lim * k;
T.Insert(rt[ver], 1, Lim * 2, (Line) {k, b, ver});
}
inline ll Query(int ver) {
int tmp = T.Query(rt[ver], 1, Lim * 2, A[ver] + Lim).id;
return 1ll * A[ver] * B[tmp] + dp[tmp];
}
void Dp(int u, int fa) {
for (int v : G[u]) if (v ^ fa)
Dp(v, u), rt[u] = T.Merge(rt[u], rt[v], 1, Lim * 2);
dp[u] = Query(u); Insert(u);
}
int main () {
File();
n = read();
For (i, 1, n) A[i] = read();
For (i, 1, n) B[i] = read();
For (i, 1, n - 1) {
int u = read(), v = read();
G[u].push_back(v); G[v].push_back(u);
}
Dp(1, 0); For (i, 1, n) printf ("%lld%c", dp[i], i == iend ? '\n' : ' ');
return 0;
}
Codeforces Round #463 F. Escape Through Leaf (李超线段树合并)的更多相关文章
- Codeforces 1303G - Sum of Prefix Sums(李超线段树+点分治)
Codeforces 题面传送门 & 洛谷题面传送门 个人感觉这题称不上毒瘤. 首先看到选一条路径之类的字眼可以轻松想到点分治,也就是我们每次取原树的重心 \(r\) 并将路径分为经过重心和不 ...
- Codeforces 1175G - Yet Another Partiton Problem(李超线段树)
Codeforces 题面传送门 & 洛谷题面传送门 这是一道李超线段树的毒瘤题. 首先我们可以想到一个非常 trivial 的 DP:\(dp_{i,j}\) 表示前 \(i\) 个数划 ...
- [Codeforces Round #296 div2 D] Clique Problem 【线段树+DP】
题目链接:CF - R296 - d2 - D 题目大意 一个特殊的图,一些数轴上的点,每个点有一个坐标 X,有一个权值 W,两点 (i, j) 之间有边当且仅当 |Xi - Xj| >= Wi ...
- codeforces 893F - Physical Education Lessons 动态开点线段树合并
https://codeforces.com/contest/893/problem/F 题意: 给一个有根树, 多次查询,每次查询对于$x$i点的子树中,距离$x$小于等于$k$的所有点中权值最小的 ...
- Codeforces 671D Roads in Yusland [树形DP,线段树合并]
洛谷 Codeforces 这是一个非正解,被正解暴踩,但它还是过了. 思路 首先很容易想到DP. 设\(dp_{x,i}\)表示\(x\)子树全部被覆盖,而且向上恰好延伸到\(dep=i\)的位置, ...
- Codeforces 666E Forensic Examination(广义后缀自动机+线段树合并)
将所有串(包括S)放一块建SAM.对于询问,倍增定位出该子串所在节点,然后要查询的就是该子串在区间内的哪个字符串出现最多.可以线段树合并求出该节点在每个字符串中的出现次数. #include<b ...
- Codeforces Round #244 (Div. 2) B. Prison Transfer 线段树rmq
B. Prison Transfer Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/pro ...
- Codeforces Round #603 (Div. 2) E. Editor(线段树)
链接: https://codeforces.com/contest/1263/problem/E 题意: The development of a text editor is a hard pro ...
- Educational Codeforces Round 6 E. New Year Tree dfs+线段树
题目链接:http://codeforces.com/contest/620/problem/E E. New Year Tree time limit per test 3 seconds memo ...
随机推荐
- mybatis的mapper注入失败
因为处在两个不同的资源文件夹下: 导致classpath无法加载其中一些文件,所以修改为classpath*后顺利进行. <!-- 加载spring容器 --> <!-- neede ...
- Elasticsearch - 简单介绍
Elasticsearch 简介 1. 什么是 Elasticsearch ElasticSearch 是一个基于 Lucene 的搜索服务器. 它了一个分布式多 用户能力的全文搜索引擎,能够达到实时 ...
- 【kindle笔记】之 《浪潮之巅》- 2018-1-
<浪潮之巅> 这本书推荐自最爱的政治课老师. 政治课老师张巍老师.我会一直记得你的. 以这样的身份来到这个学校,他人的质疑,自己的忐忑,老板的不公.犹犹豫豫谨小慎微地前进. 第一次听到这样 ...
- Android下的软件合集
在平常使用Android手机的时候,选择一个好的软件可以做到事半功倍的效果,所以在此总结一下,加速我们的工作与生活效率 1) ConnectBot ConnectBot是一个Android操作系统上的 ...
- C#复习笔记(3)--C#2:解决C#1的问题(泛型)
这一章会描述在C#2中所做的主要的变化 泛型 泛型的概念中包含类型参数和类型实参,类型参数相当于类型实参的蓝图. 泛型类型分为未绑定泛型类型和已构造泛型类型.已构造泛型类型又分为开放的泛型类型和封闭的 ...
- apach ab 安装时的错误
1.cmd进入bin下:执行httpd -k install 需要管理员 登陆安装 我们打开conf文件夹,找到httpd.conf,修改如下内容,让serverroot指向你的安装位置: Defin ...
- Bootstrap 字体图标(Glyphicons)
http://www.runoob.com/bootstrap/bootstrap-glyphicons.html 什么是字体图标? 字体图标是在 Web 项目中使用的图标字体.虽然,Glyphico ...
- MyBatis映射文件3(参数处理Map)
参数命名 POJO 如果多个参数,正好是业务逻辑的数据模型,那么我们就可以直接传入POJO,这样#{}中就可以直接使用属性名 Map 如果多个参数不是业务逻辑的数据模型,没有对应的POJO,为了方便, ...
- Spark开发第一个程序
simon@simon-Lenovo-G400:~/.ssh$ touch authorized_keyssimon@simon-Lenovo-G400:~/.ssh$ cat id_rsa.pub ...
- centso7 安装redmine
一.安装rvm ###安装rvm gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D3 ...