有点类似NOI2014购票

  首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$

  这个显然是可以斜率优化的...

  $\frac {f(j)-f(k)}{dep_j-dep_k}<p_i$

  $p_i$是单调的,于是可以单调队列,当遍历完一个子树的时候,必须复原单调队列到进入这棵子树前的样子,这个用可持久化线段树维护可持久化数组显然可做...

  当然有更聪明的方法。

  单调队列队头出去的时候实际上队列信息不会被覆盖,于是恢复左端点只要记录进入当前点前的左端点即可。

  右端点可能会被覆盖,但是每次最多覆盖一个点(也就是当前点),于是恢复右端点只需要记录进入当前点前的右端点和被覆盖的值即可。

  但是这么做的话无法保证一个点出队入队次数是常数级别的,也就无法保证复杂度是$O(n)$了,所以每次不能一个一个出队(一条链加一朵大菊花就可以卡了),必须二分出队位置,才可以保证复杂度,做到$O(nlogn)$。

  但是出题人没有卡暴力出队的做法...我写二分比直接暴力弹出跑得快= =... 事实证明是评测机玄学...有时候跑得快有时候跑得慢

二分:

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#define ll long long
using namespace std;
const int maxn=, inf=1e9;
struct poi{int too, dis, pre;}e[maxn];
int n, x, z, tot, l, r;
int p[maxn], Q[maxn], last[maxn], nowl[maxn], nowr[maxn], nowqr[maxn], q[maxn];
ll f[maxn], d[maxn];
inline void read(int &k)
{
int f=; k=; char c=getchar();
while(c<'' || c>'') c=='-' && (f=-), c=getchar();
while(c<='' && c>='') k=k*+c-'', c=getchar();
k*=f;
}
inline void add(int x, int y, int z){e[++tot]=(poi){y, z, last[x]}; last[x]=tot;}
inline double xl(int j, int k){return 1.0*(f[j]-f[k])/(d[j]-d[k]);}
inline void dfs(int x)
{
nowl[x]=l;
if(l<r)
{
int L=l, R=r-;
while(L<R)
{
int mid=(L+R)>>;
if(p[x]-xl(q[mid+], q[mid])>1e-) L=mid+;
else R=mid;
}
l=(p[x]-xl(q[L], q[L+])>1e-)?L+:L;
}
nowr[x]=r;
if(x!=) f[x]=f[q[l]]+Q[x]+1ll*(d[x]-d[q[l]])*p[x];
if(l<r)
{
int L=l+, R=r;
while(L<R)
{
int mid=(L+R+)>>;
if(xl(x, q[mid])<xl(q[mid], q[mid-])) R=mid-;
else L=mid;
}
r=(xl(x, q[L])<xl(q[L-], q[L]))?L-:L;
}
nowqr[x]=q[r+]; q[++r]=x;
for(int i=last[x], too;i;i=e[i].pre) d[too=e[i].too]=d[x]+e[i].dis, dfs(too);
l=nowl[x]; q[r]=nowqr[x]; r=nowr[x];
}
int main()
{
read(n);
for(int i=;i<=n;i++) read(x), read(z), add(x, i, z), read(p[i]), read(Q[i]);
l=; r=; dfs();
for(int i=;i<=n;i++) printf("%lld\n", f[i]);
}

暴力出队:

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#define ll long long
using namespace std;
const int maxn=, inf=1e9;
struct poi{int too, dis, pre;}e[maxn];
int n, x, z, tot, l, r;
int p[maxn], Q[maxn], last[maxn], nowl[maxn], nowr[maxn], nowqr[maxn], q[maxn];
ll f[maxn], d[maxn];
inline void read(int &k)
{
int f=; k=; char c=getchar();
while(c<'' || c>'') c=='-' && (f=-), c=getchar();
while(c<='' && c>='') k=k*+c-'', c=getchar();
k*=f;
}
inline void add(int x, int y, int z){e[++tot]=(poi){y, z, last[x]}; last[x]=tot;}
inline double xl(int j, int k){return 1.0*(f[j]-f[k])/(d[j]-d[k]);}
inline void dfs(int x)
{
nowl[x]=l; while(l<r && p[x]-xl(q[l+], q[l])>1e-) l++;
if(x!=) f[x]=f[q[l]]+Q[x]+1ll*(d[x]-d[q[l]])*p[x];
nowr[x]=r; while(l<r && xl(x, q[r])<xl(q[r], q[r-])) r--;
nowqr[x]=q[r+]; q[++r]=x;
for(int i=last[x], too;i;i=e[i].pre) d[too=e[i].too]=d[x]+e[i].dis, dfs(too);
l=nowl[x]; q[r]=nowqr[x]; r=nowr[x];
}
int main()
{
read(n);
for(int i=;i<=n;i++) read(x), read(z), add(x, i, z), read(p[i]), read(Q[i]);
l=; r=; dfs();
for(int i=;i<=n;i++) printf("%lld\n", f[i]);
}

洛谷P3994 Highway(树形DP+斜率优化+可持久化线段树/二分)的更多相关文章

  1. P3994 高速公路 树形DP+斜率优化+二分

    $ \color{#0066ff}{ 题目描述 }$ C国拥有一张四通八达的高速公路网树,其中有n个城市,城市之间由一共n-1条高速公路连接.除了首都1号城市,每个城市都有一家本地的客运公司,可以发车 ...

  2. 洛谷P4027 [NOI2007]货币兑换(dp 斜率优化 cdq 二分)

    题意 题目链接 Sol 解题的关键是看到题目里的提示... 设\(f[i]\)表示到第\(i\)天所持有软妹币的最大数量,显然答案为\(max_{i = 1}^n f[i]\) 转移为\(f_i = ...

  3. bzoj3672: [Noi2014]购票(树形DP+斜率优化+可持久化凸包)

    这题的加强版,多了一个$l_i$的限制,少了一个$p_i$的单调性,难了好多... 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ $\frac {f(j) ...

  4. 洛谷P2365 任务安排(斜率优化dp)

    传送门 思路: 最朴素的dp式子很好考虑:设\(dp(i,j)\)表示前\(i\)个任务,共\(j\)批的最小代价. 那么转移方程就有: \[ dp(i,j)=min\{dp(k,j-1)+(sumT ...

  5. 洛谷P2120 [ZJOI2007]仓库建设 斜率优化DP

    做的第一道斜率优化\(DP\)QwQ 原题链接1/原题链接2 首先考虑\(O(n^2)\)的做法:设\(f[i]\)表示在\(i\)处建仓库的最小费用,则有转移方程: \(f[i]=min\{f[j] ...

  6. 洛谷4072 SDOI2016征途 (斜率优化+dp)

    首先根据题目中给的要求,推一下方差的柿子. \[v\times m^2 = m\times \sum x^2 - 2 \times sum \times sum +sum*sum \] 所以\(ans ...

  7. Codeforces 1179D 树形DP 斜率优化

    题意:给你一颗树,你可以在树上添加一条边,问添加一条边之后的简单路径最多有多少条?简单路径是指路径中的点只没有重复. 思路:添加一条边之后,树变成了基环树.容易发现,以基环上的点为根的子树的点中的简单 ...

  8. 洛谷P4072 [SDOI2016]征途(斜率优化)

    传送门 推式子(快哭了……)$$s^2*m^2=\sum _{i=1}^m (x_i-\bar{x})^2$$ $$s^2*m^2=m*\sum _{i=1}^m x_i^2-2*sum_n\sum ...

  9. 洛谷3571 POI2014 SUP-Supercomputer (斜率优化)

    一道神仙好题. 首先看到有多组\(k\),第一反应就是离线. 考虑贪心. 我们每次一定是尽量选择有儿子的节点.以便于我们下一次扩展. 但是对于一个\(k\),每次贪心的复杂度是\(O(n)\) 总复杂 ...

随机推荐

  1. yocto-sumo源码解析(六): setup_bitbake

    1. 创造日志handler: 在status_only模式,不需要日志以及UI # Ensure logging messages get sent to the UI as events hand ...

  2. ossec安装

    安装 安装要求 对于Unix系统来说,OSSEC只需要GNU的make.gcc和libc.推荐使用OpenSSL,但仅属于一个可选项.而且,通常您只需在一个系统上做编译操作,然后将二进制程序复制到其他 ...

  3. nodejs 中 module.exports 和 exports 的区别

    1. module应该是require方法中,上下文中的对象 2. exports对象应该是上下文中引用module.exports的新对象 3. exports.a = xxx 会将修改更新到mod ...

  4. wf4 FlowChart 理解

    1. 工作流是异步的,所以需要信号. 2. 需要创建 NativeActivity<T> 与整个FlowChart交互. 它的返回值 Result 正确含义是 该 Activity处理之后 ...

  5. PHP Filter 函数 日常可用

    PHP Filter 函数 PHP Filesystem PHP FTP PHP Filter 简介 PHP 过滤器用于对来自非安全来源的数据(比如用户输入)进行验证和过滤. 安装 filter 函数 ...

  6. “Hello World!”团队第六周的第三次会议

    今天是我们团队“Hello World!”团队第六周召开的第三次会议.博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七.燃尽图 八.代码 一 ...

  7. 冲刺One之站立会议7 /2015-5-20

    2015-5-20 在登陆成功之后要实现的是聊天界面的交互过程,不同的IP进行信息和数据的传递,这方面我们上学期Java实验里面有过相关的内容,我们把它拿过来改了一下格式,试着看能不能成功,目前还没实 ...

  8. 《Spring2之站立会议2》

    <Spring2之站立会议2> 昨天,模仿着资料把客户端和服务器端的代码写了一下: 今天,继续找本机的端口号和逐步深入理解代码含义: 遇到的问题,在理解时,对一些知识理解还是比较朦胧,一知 ...

  9. 课堂练习 psp表

    项目计划总结表: 日期 编程 完善程序 测试程序 参考资料 日总结 3.20 18:00---19:30       1.5 3.21   9:30----10:00 10:00---10:30   ...

  10. BufferedWriter与BufferedRead --------------------------Test2

    package com.test; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; ...