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

$$\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. What Kind of Friends Are You? ZOJ - 3960(ZheJiang Province Contest)

    怎么说呢...我能说我又过了一道水题? emm... 问题描述: 给定 n 个待确定名字的 Friends 和 q 个问题.已知 c 个 Friends 的名字. 对于第 i 个问题,有  个 Fri ...

  2. [BZOJ2095][Poi2010]Bridges 最大流(混合图欧拉回路)

    2095: [Poi2010]Bridges Time Limit: 10 Sec  Memory Limit: 259 MB Description YYD为了减肥,他来到了瘦海,这是一个巨大的海, ...

  3. Laravel4快速安装方法,解决Laravel4安装速度慢

    Laravel4原始安装方法 Laravel4 是构建在 Composer 之上的, 之前的安装方法是如下:   composer create-project laravel/laravel you ...

  4. 整理:python的二维数组操作

    Python中初始化一个5 x 3每项为0的数组,最好方法是: multilist = [[0 for col in range(5)] for row in range(3)] 如果初始化一个二维数 ...

  5. 洛谷3732:[HAOI2017]供给侧改革——题解

    https://www.luogu.org/problemnew/show/P3732 Anihc国提高社会生产力水平.落实好以人民为中心的发展思想.决定进行供给侧结构性改革. 为了提高供给品质.你调 ...

  6. 【bzoj3575】 Hnoi2014—道路堵塞

    http://www.lydsy.com/JudgeOnline/problem.php?id=3575 (题目链接) 题意 给出一个有向图和一条最短路,问最短路上任意一条边断掉,此时的最短路是多少. ...

  7. 关于JavaScript诞生之初的趣事

    我在读很多优秀的JavaScript源码时候常常被它诡异的语法搞的精疲力尽,所以时不时的加固JavaScript基础知识是十分有必要的,这些知识每次温故或者你换个角度去思考都能收获颇多,那么如此深不可 ...

  8. web页面的绝对路径

    在JavaWeb开发中,常使用绝对路径的方式来引入JavaScript和CSS文件,这样可以避免因为目录变动导致引入文件找不到的情况,常用的做法如下:一.使用${pageContext.request ...

  9. UVALive 7505 Hungry Game of Ants (2015Ecfinal)

    题意: 长度是n的线段上点的编号从1~n,每个点有一只蚂蚁蚂蚁的体重等于该点的编号,最初每只蚂蚁可以选择向右走或者向左走两只蚂蚁相遇时体重大的吃掉体重小的并且体重增加为两只的体重和,走到边界时掉头,问 ...

  10. ORM choice字段 如何在页面上显示值

    核心:obj.get_字段名_display 1.定义module 数据结构: class msg(models.Model): choice = ( (1, '技术部'), (2, '行政'), ( ...