洛谷P3994 Highway(树形DP+斜率优化+可持久化线段树/二分)
有点类似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+斜率优化+可持久化线段树/二分)的更多相关文章
- P3994 高速公路 树形DP+斜率优化+二分
$ \color{#0066ff}{ 题目描述 }$ C国拥有一张四通八达的高速公路网树,其中有n个城市,城市之间由一共n-1条高速公路连接.除了首都1号城市,每个城市都有一家本地的客运公司,可以发车 ...
- 洛谷P4027 [NOI2007]货币兑换(dp 斜率优化 cdq 二分)
题意 题目链接 Sol 解题的关键是看到题目里的提示... 设\(f[i]\)表示到第\(i\)天所持有软妹币的最大数量,显然答案为\(max_{i = 1}^n f[i]\) 转移为\(f_i = ...
- bzoj3672: [Noi2014]购票(树形DP+斜率优化+可持久化凸包)
这题的加强版,多了一个$l_i$的限制,少了一个$p_i$的单调性,难了好多... 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ $\frac {f(j) ...
- 洛谷P2365 任务安排(斜率优化dp)
传送门 思路: 最朴素的dp式子很好考虑:设\(dp(i,j)\)表示前\(i\)个任务,共\(j\)批的最小代价. 那么转移方程就有: \[ dp(i,j)=min\{dp(k,j-1)+(sumT ...
- 洛谷P2120 [ZJOI2007]仓库建设 斜率优化DP
做的第一道斜率优化\(DP\)QwQ 原题链接1/原题链接2 首先考虑\(O(n^2)\)的做法:设\(f[i]\)表示在\(i\)处建仓库的最小费用,则有转移方程: \(f[i]=min\{f[j] ...
- 洛谷4072 SDOI2016征途 (斜率优化+dp)
首先根据题目中给的要求,推一下方差的柿子. \[v\times m^2 = m\times \sum x^2 - 2 \times sum \times sum +sum*sum \] 所以\(ans ...
- Codeforces 1179D 树形DP 斜率优化
题意:给你一颗树,你可以在树上添加一条边,问添加一条边之后的简单路径最多有多少条?简单路径是指路径中的点只没有重复. 思路:添加一条边之后,树变成了基环树.容易发现,以基环上的点为根的子树的点中的简单 ...
- 洛谷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 ...
- 洛谷3571 POI2014 SUP-Supercomputer (斜率优化)
一道神仙好题. 首先看到有多组\(k\),第一反应就是离线. 考虑贪心. 我们每次一定是尽量选择有儿子的节点.以便于我们下一次扩展. 但是对于一个\(k\),每次贪心的复杂度是\(O(n)\) 总复杂 ...
随机推荐
- Django_分页
目录 基本语法 示例 示例1 使用django内置Paginator模块 示例2 改写Paginator 示例3 自定义pager组件 示例3.1 objs与pager各自单独使用 示例3.2 obj ...
- Linux下oracle启动/关闭监听(bash:lsnrctl:command not found)
打开终端 切换帐户 # su - Oracle 启动监听 $ lsnrctl start 关闭监听 $ lsnrctl stop 切换帐户一定要加 "-" 否则会出现: bas ...
- SpringMvc跨域支持
SpringMvc跨域支持 在controller层加上注解@CrossOrigin可以实现跨域 该注解有两个参数 1,origins : 允许可访问的域列表 2,maxAge:飞行前响应的缓存持续 ...
- 20162314 《Program Design & Data Structures》Learning Summary Of The Seventh Week
20162314 2017-2018-1 <Program Design & Data Structures>Learning Summary Of The Seventh Wee ...
- SQLyog的基本使用
[简介] SQLyog是mysql数据库的客户端软件 [基本使用] 1.连接mysql数据库 2.SQLyog的页面使用介绍 3.基本的数据库命令 1) use命令 切换数据库 2) unsigned ...
- MYSQL-不能创建表
Can't create table '.\ticket\user_role.frm' (errno: 121) 语法是对的,但显示上面的错误 原因有三种 1.表名重复 2.以该名字命名的表之前创建过 ...
- 我是IT小小鸟读后感
<我是一只IT小小鸟>一只是我想读list中一个本,但是上次去当当买的时候,竟然缺货了...昨天监考,实在无聊,就上网看电子书了,一天就看完了,看得有点仓促,所以理解估计不深. 1.刘帅: ...
- 动态生成CheckBox(Winform程序)
在做用户权限设置功能时,需要做一个动态生成权限列表的功能.(笔记.分享) //1.清空权限控件组的默认控件 panelPermissions.Controls.Clear(); _groupBoxLi ...
- 用虚拟机安装了一台Linux系统,突然想克隆一台服务器,克隆后发现无法上网,如何解决?
用虚拟机安装了一台Linux系统,突然想克隆一台服务器,克隆后发现无法上网,如何解决? 答: a.编辑网卡配置文件/etc/sysconfig/network-scripts/ifcfg-eth ...
- JMeter性能测试基础 (2) - 变量的使用
在使用JMeter进行性能测试时,一般情况下要保证样本容量尽可能大,这样才能得到一个比较合理的结果.也就是说,我们不能只对同一个URL进行多次访问,而是要对统一模块下尽可能多的URL进行访问,以取得相 ...