建议到UOJ上去交

题解

一眼\(DP\),先把转移方程写出来

设\(dp[i]\)为从点\(i\)出发到点\(1\)的最小费用,那么存在转移

\[f[i]=min\{f[j]+(d[i]-d[j])p[i]\}+q[i]=min\{f[j]-d[j]p[i]\}+d[i]*p[i]+q[i]
\]

这个式子看起来可以斜率优化啊,往下化几步,可以得到类似下面的东西:

若\(d[j] < d[k]\),则当\(\frac{dp[j]-dp[k]}{d[j]-d[k]}\geqslant p[i]\)时从\(j\)转移更优,否则从\(k\)转移更优

这表明我们只需要维护一个下凸壳,转移时二分一下就行了

假设这个问题是在序列上且没有距离限制,你就已经可以\(O(nlogn)\)地\(A\)掉它了

加上距离限制时,我们可以拿个线段树维护一下每一小段的凸壳,查询时取个最大值

挪到树上时,只需要上个树剖

托上面两个东西的福,复杂度也变成了\(O(nlog^3n)\)[手动滑稽]

然后就是码码码

#include <bits/stdc++.h>

using namespace std;

#define MAXN 200000
#define vi vector<int>
#define pb push_back
#define ll long long
#define INF 0x7f7f7f7f7f7f7f7f
#define LIM 17 int n, t;
vi G[MAXN + 5];
int summit[MAXN + 5], f[20][MAXN + 5], fa[MAXN + 5], top[MAXN + 5], sz[MAXN + 5], hson[MAXN + 5], id[MAXN + 5], dfn[MAXN + 5], dfn_clk;
ll d[MAXN + 5], s[MAXN + 5], p[MAXN + 5], q[MAXN + 5], l[MAXN + 5], dp[MAXN + 5]; namespace HLD {
void dfs1(int u) {
sz[u] = 1;
f[0][u] = fa[u];
for (int i = 1; i <= LIM; ++i) f[i][u] = f[i - 1][f[i - 1][u]];
for (auto v : G[u]) {
if (v == fa[u]) continue;
d[v] = d[u] + s[v];
dfs1(v);
sz[u] += sz[v];
if (sz[v] > sz[hson[u]]) hson[u] = v;
}
} void dfs2(int u, int tp) {
top[u] = tp;
dfn[u] = ++dfn_clk;
id[dfn_clk] = u;
if (hson[u]) dfs2(hson[u], tp);
for (auto v : G[u]) {
if (v == fa[u] || v == hson[u]) continue;
dfs2(v, v);
}
}
} double slope(int x, int y) {
return static_cast<double>(dp[y] - dp[x])/(d[y] - d[x]);
} void pre() {
for (int i = 2; i <= n; ++i) {
int u = i;
for (int j = LIM; ~j; --j)
if (d[i] - d[f[j][u]] <= l[i])
u = f[j][u];
summit[i] = !u ? 1 : u;
}
} namespace SegementTree {
#define mid ((l + r) >> 1)
#define lson (o << 1)
#define rson (o << 1 | 1) vi ch[4 * MAXN + 5]; void addPoint(vi &v, int x) { // 把点x扔进下凸壳
while (v.size() >= 2 && slope(x, v[v.size() - 2]) < slope(v[v.size() - 1], v[v.size() - 2])) v.pop_back();
v.push_back(x);
} ll get(vi &v, ll p) { // 在凸壳上二分斜率
if (v.size() == 1) return dp[v[0]] - d[v[0]] * p;
ll ret = INF;
int l = 0, r = v.size() - 1, m;
double s1, s2;
while (l <= r) {
m = (l + r) >> 1;
if (m == v.size() - 1) {
s1 = slope(v[m - 1], v[m]);
ret = min(ret, dp[v[m]] - d[v[m]] * p);
if (s1 <= p) l = m + 1;
else r = m - 1;
}
else if (!m) {
s2 = slope(v[m], v[m + 1]);
ret = min(ret, dp[v[m]] - d[v[m]] * p);
if (s2 <= p) l = m + 1;
else r = m - 1;
}
else {
s1 = slope(v[m - 1], v[m]);
s2 = slope(v[m], v[m + 1]);
ret = min(ret, dp[v[m]] - d[v[m]] * p);
if (s1 <= p && s2 <= p) l = m + 1;
else if(s1 <= p && s2 > p) return min(ret, dp[v[m]] - d[v[m]] * p);
else r = m - 1;
}
}
return ret;
} void insert(int o, int l, int r, int x, int u) { // 插入一个点
addPoint(ch[o], u);
if (l == r) return ;
if (x <= mid) insert(lson, l, mid, x, u);
else insert(rson, mid + 1, r, x, u);
} ll query(int o, int l, int r, int L, int R, ll p) { // 在那一堆凸壳中找最小值
if (L <= l && r <= R) return get(ch[o], p);
ll ret = INF;
if (L <= mid) ret = min(ret, query(lson, l, mid, L, R, p));
if (R > mid) ret = min(ret, query(rson, mid + 1, r, L, R, p));
return ret;
} #undef mid
#undef lson
#undef rson
}
using namespace SegementTree; void update(int u) { // 求点u的DP值
dp[u] = INF;
int x = fa[u];
while (d[top[x]] >= d[summit[u]]) {
dp[u] = min(dp[u], query(1, 1, n, dfn[top[x]], dfn[x], p[u]) + d[u] * p[u] + q[u]);
x = fa[top[x]];
}
if (d[x] >= d[summit[u]]) dp[u] = min(dp[u], query(1, 1, n, dfn[summit[u]], dfn[x], p[u]) + d[u] * p[u] + q[u]);
} void work(int u) {
if (u != 1) update(u);
insert(1, 1, n, dfn[u], u);
for (auto v : G[u]) {
if (v == fa[u]) continue;
work(v);
}
} int main() {
scanf("%d%d", &n, &t);
for (int i = 2; i <= n; ++i) {
scanf("%d%lld%lld%lld%lld", &fa[i], &s[i], &p[i], &q[i], &l[i]);
G[fa[i]].pb(i);
}
HLD::dfs1(1);
HLD::dfs2(1, 1);
d[0] = -1;
pre();
work(1);
for (int i = 2; i <= n; ++i) printf("%lld\n", dp[i]);
return 0;
}

最新文章

  1. python单元测试unittest
  2. CDH5X 安装oozie报错To enable Oozie web console install the Ext JS library.
  3. mybatis多表连接在一起查询
  4. Testing - 测试基础 - 探索
  5. load、init和initialize的区别
  6. LCT小结
  7. JS运动学习笔记 -- 任意值的运动框架(高/宽度,背景颜色,文本内容,透明度等)
  8. git设置对比工具
  9. java开发者最常去的20个英文网站
  10. 动态缓存技术之CSI,SSI,ESI
  11. android开发 单击按钮 实现页面间的跳转
  12. xmanager 使用
  13. OpenGL———混合的基本知识
  14. hdfs创建删除文件和文件夹
  15. A.01.10—模块的输出—PWM高端输出
  16. JavaScript中创建对象的几种模式
  17. jQuery获取URL中的参数
  18. msf客户端渗透(一):payload利用简单示范
  19. mfc CTabCtrl
  20. 鬼知道是啥系列之——STL(lower_bound(),upper_bound() )

热门文章

  1. js 跳转传递汉字参数
  2. 小菜鸟之liunx
  3. mybatis缓存机制与装饰者模式
  4. Windows32位或64位下载安装配置Scala
  5. python — 协程
  6. 《深入理解 Java 虚拟机》学习 -- 类加载机制
  7. postman中传参说明
  8. Js 判断数组中是否包含某个值
  9. sql游标循环
  10. c++11 原生字符串字面值