首先易得方程,且经过变换有

$$\begin{aligned} f_i &= \min\limits_{dist_i - lim_i \le dist_j} \{f_j + (dist_i - dist_j)p_i + q_i\} \\ f_j &= p_idist_j + f_i - dist_ip_i - q_i \end{aligned}$$

在一条直线上时,斜率优化可以用普通$CDQ$分治实现(会不会过于麻烦?),那么对于在树上斜率优化时,考虑点分治

这时就在点分治中运用$CDQ$分治的思想,即使用在当前重心管辖范围内的通向根节点的那一条链上的节点来更新其它节点就好了

注意在分治中的斜率优化时在凸包上加点和更新右侧节点答案要同时进行,不然当前最优解可能会在后面由于斜率被删去,导致答案错误,还有由于下面代码是由深度由小到大处理的,所以是反着维护下凸包,即上凸包

代码

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath> using namespace std; typedef long long LL; const int MAXN = 2e05 + ;
const int MAXM = 2e05 + ; const int INF = 0x7fffffff;
const LL INFLL = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-; int Dcmp (double p) {
if (fabs (p) < eps)
return ;
return p < ? - : ;
} struct LinkedForwardStar {
int to; int next;
} ; LinkedForwardStar Link[MAXM << ];
int Head[MAXN]= {};
int size = ; void Insert (int u, int v) {
Link[++ size].to = v;
Link[size].next = Head[u]; Head[u] = size;
} const int Root = ; struct CitySt {
LL p, q, lim; CitySt () {}
} ;
CitySt City[MAXN]; LL f[MAXN]; int N;
LL Fdist[MAXN]= {}; LL Dist[MAXN]= {};
int Father[MAXN]= {};
void DFS (int root, int father) {
for (int i = Head[root]; i; i = Link[i].next) {
int v = Link[i].to;
if (v == father)
continue;
Dist[v] = Dist[root] + Fdist[v];
DFS (v, root);
}
} int Vis[MAXN]= {}; int Size[MAXN]= {};
int grvy, minval = INF;
int total;
void Grvy_Acqu (int root, int father) {
Size[root] = ;
int maxpart = ;
for (int i = Head[root]; i; i = Link[i].next) {
int v = Link[i].to;
if (v == father || Vis[v])
continue;
Grvy_Acqu (v, root);
Size[root] += Size[v];
maxpart = max (maxpart, Size[v]);
}
maxpart = max (maxpart, total - Size[root]);
if (maxpart < minval)
grvy = root, minval = maxpart;
} int temp[MAXN];
int p = ;
int Que[MAXN];
double slope (int a, int b) {
if (Dist[a] == Dist[b])
return INFLL * 1.0;
return (double) (f[b] - f[a]) * 1.0 / (double) (Dist[b] - Dist[a]) * 1.0;
}
int listq[MAXN];
int lp = ;
bool comp (const int& a, const int& b) {
return Dist[a] - City[a].lim > Dist[b] - City[b].lim;
}
void listq_Acqu (int root, int father) {
if (father)
listq[++ lp] = root;
for (int i = Head[root]; i; i = Link[i].next) {
int v = Link[i].to;
if (v == father || Vis[v])
continue;
listq_Acqu (v, root);
}
}
int Binary_Search (int left, int right, int p) {
if (left == right)
return left;
int l = left, r = right;
while (l < r) {
int mid = (l + r) >> ;
if (f[Que[mid + ]] - f[Que[mid]] <= p * (Dist[Que[mid + ]] - Dist[Que[mid]]))
l = mid + ;
else
r = mid;
}
return l;
}
void Update (int left, int right, int tp) {
if (left > right)
return ;
int p = Binary_Search (left, right, City[tp].p);
f[tp] = min (f[tp], f[Que[p]] + (Dist[tp] - Dist[Que[p]]) * City[tp].p + City[tp].q);
}
void Solve (int root) {
minval = INF, total = Size[root], Grvy_Acqu (root, );
Vis[grvy] = true;
int fgrvy = grvy;
if (grvy != root) {
Size[root] -= Size[grvy];
Solve (root);
}
p = ;
temp[++ p] = fgrvy;
for (int nd = fgrvy; nd != root; nd = Father[nd]) {
if (Dist[fgrvy] - City[fgrvy].lim <= Dist[Father[nd]])
f[fgrvy] = min (f[fgrvy], f[Father[nd]] + (Dist[fgrvy] - Dist[Father[nd]]) * City[fgrvy].p + City[fgrvy].q);
temp[++ p] = Father[nd];
}
lp = ;
listq_Acqu (fgrvy, );
sort (listq + , listq + lp + , comp);
int left = , right = ;
int j = ;
for (int i = ; i <= p && j <= lp; i ++) { // 斜率优化
while (j <= lp && Dist[temp[i]] < Dist[listq[j]] - City[listq[j]].lim)
Update (left, right, listq[j ++]);
while (left < right && Dcmp (slope (Que[right - ], Que[right]) - slope (Que[right], temp[i])) <= ) // 注意是上凸包
right --;
Que[++ right] = temp[i];
}
while (j <= lp)
Update (left, right, listq[j ++]);
for (int i = Head[fgrvy]; i; i = Link[i].next) {
int v = Link[i].to;
if (Vis[v])
continue;
Solve (v);
}
} int getint () {
int num = ;
char ch = getchar (); while (! isdigit (ch))
ch = getchar ();
while (isdigit (ch))
num = (num << ) + (num << ) + ch - '', ch = getchar (); return num;
} LL getLL () {
LL num = ;
char ch = getchar (); while (! isdigit (ch))
ch = getchar ();
while (isdigit (ch))
num = (num << ) + (num << ) + ch - '', ch = getchar (); return num;
} int main () {
// freopen ("Input.txt", "r", stdin);
// freopen ("Output.txt", "w", stdout); memset (f, 0x3f3f3f3f, sizeof (f));
f[Root] = ;
N = getint (), getint ();
for (int i = ; i <= N; i ++) {
int fa = getint ();
Father[i] = fa;
Fdist[i] = getLL ();
City[i].p = getLL (), City[i].q = getLL (), City[i].lim = getLL ();
Insert (fa, i), Insert (i, fa);
}
DFS (Root, );
Size[Root] = N;
Solve (Root);
for (int i = ; i <= N; i ++)
printf ("%lld\n", f[i]); return ;
} /*
7 3
1 2 20 0 3
1 5 10 100 5
2 4 10 10 10
2 9 1 100 10
3 5 20 100 10
4 4 20 0 10
*/

[NOI2014]购票 「树上斜率优化」的更多相关文章

  1. BZOJ_3672_ [Noi2014]购票_CDQ分治+斜率优化

    BZOJ_3672_ [Noi2014]购票_CDQ分治+斜率优化 Description  今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参 ...

  2. 【BZOJ3672】[Noi2014]购票 树分治+斜率优化

    [BZOJ3672][Noi2014]购票 Description  今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会.       ...

  3. 【BZOJ-3672】购票 树分治 + 斜率优化DP

    3672: [Noi2014]购票 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1177  Solved: 562[Submit][Status][ ...

  4. [洛谷U22158]策划体验(树上斜率优化)(二分最优决策)

    题目背景 OL不在,Clao又在肝少*前线,他虽然觉得这个游戏的地图很烦,但是他认为地图的难度还是太低了,习习中作为策划还不够FM,于是他自己YY了一种新的地图和新的机制: 题目描述 整个地图呈树形结 ...

  5. UOJ#7. 【NOI2014】购票 点分治 斜率优化 凸包 二分

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ7.html 题解 这题是Unknown的弱化版. 如果这个问题出在序列上,那么显然可以CDQ分治 + 斜率 ...

  6. [NOI2007]货币兑换 「CDQ分治实现斜率优化」

    首先每次买卖一定是在某天 $k$ 以当时的最大收入买入,再到第 $i$ 天卖出,那么易得方程: $$f_i = \max \{\frac{A_iRate_kf_k}{A_kRate_k + B_k} ...

  7. [Bzoj1767][Ceoi2009]harbingers (树上斜率优化)

    1767: [Ceoi2009]harbingers Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 451  Solved: 120[Submit][S ...

  8. HDU - 59562016ACM/ICPC亚洲区沈阳站I - The Elder 树上斜率优化dp

    题意:给定上一棵树,然后每条边有一个权值,然后每个点到 1 的距离有两种,第一种是直接回到1,花费是 dist(1, i)^2,还有另一种是先到另一个点 j,然后两从 j 向1走,当然 j 也可以再向 ...

  9. ☆ [洛谷P2633] Count on a tree 「树上主席树」

    题目类型:主席树+\(LCA\) 传送门:>Here< 题意:给出一棵树.每个节点有点权.问某一条路径上排名第\(K\)小的点权是多少 解题思路 类似区间第\(K\)小,但放在了树上. 考 ...

随机推荐

  1. [UVALive 3902] Network

    图片加载可能有点慢,请跳过题面先看题解,谢谢 一道简单的贪心题,而且根节点已经给你了(\(S\)),这就很好做了. 显然,深度小于等于 \(k\) 的都不用管了(\(S\) 深度为0),那么我们只需要 ...

  2. Alpha 冲刺 —— 十分之七

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 学习MSI.CUDA 试运行软件并调试 ...

  3. BZOJ5058 期望逆序对 【矩乘 + 组合数学 + 树状数组】

    题目链接 BZOJ5058 题解 可以发现任意两个位置\(A,B\)最终位置关系的概率是相等的 如果数列是这样: CCCCACCCCBCCCC 那么最终有\(7\)种位置关系 \((A,B)\) \( ...

  4. WEB入门.七 CSS布局模型

    学习内容 标准文档流 流动模型(flow model) 浮动模型(float model) CSS基本布局 能力目标 理解标准文档流 使用流动模型实现页面布局 使用浮动模型实现页面布局 掌握常用CSS ...

  5. eclipse 支持 Robot framework 编辑环境

    一.配置python 环境     1. 设置pydev库         打开Help -> Install New Software, 点击'Add',设置Name为“Pydev”,Loca ...

  6. 浏览器json数据格式化

    在浏览器上作接口测试的时候看到json 格式的数据是密密麻麻的一片,眼睛都花了..  如: 设置方法:  chrome  的右上角选择,然后---  更多工具---  扩展程序  ----   JSO ...

  7. 线程属性API

    数据类型:pthread_attr_t 操作API: // 初始化线程属性 int pthread_attr_init(pthread_attr_t *attr);// 初始化为系统支持的所有属性的默 ...

  8. 利用ansible来做tomcat应用的持续交付

    https://www.jianshu.com/p/fca8f91ae223 在做持续交付这件事,想必大家都是用jenkins这款程序来做基石.当然,我们这次也是用jenkins作为承载工具,jenk ...

  9. Docker入门与应用系列(三)容器管理

    一.启动容器 启动容器有两种方式,一种是基于镜像新建一个容器并启动,另一个是将终止状态的容器重新启动. 1.1 新建并启动 主要命令为 docker run 下面的命令输出一个”Hello,world ...

  10. 转:UINavigationBar返回上一级出现nested pop animation can result in corrupted navigation bar

    [self.navigationController popViewControllerAnimated:NO]; 出现上面的错误是因为pop的时候要确保先让本页面加载完成,即如果在viewDidLo ...