洛谷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)\) 总复杂 ...
随机推荐
- hadoop之定制自己的sort过程
Key排序 1. 继承WritableComparator 在hadoop之Shuffle和Sort中,可以看到mapper的输出文件spill文件需要在内存中排序,并且在输入reducer之前,不同 ...
- Redis集群搭建与使用
前端时间开发中需要用到redis缓存数据,考虑到单台redis的不稳定性,后采用redis集群的方式来实现,由于之前没有接触过,过程中也是踩了不少的坑,拖了三天总算是搞定了,最近公司比较闲,总结了一下 ...
- 阿里云oracle启动失败
1.监听启动失败: 将$ORACLE_HOME/network/admin 中的listener.ora中的主机名改为localhost 2.sqlplus中startup启动失败 ,出现ORA-00 ...
- 20135234mqy 实验三:敏捷开发与XP实践
实 验 报 告 课程:Java 班级: 1352 姓名:mqy 学号:20135234 成绩: 指导教师:娄嘉鹏 实验日期:2015. ...
- eclipse 中使用git
1.安装egit插件,在新版的eclipse中已经集成了这个插件,省了不少时间, 旧版的eclipse可以在help->install new software中点击add,写入名称,网址具体如 ...
- Java未赋值变量的默认初始值
在 Java 程序中,任何变量都必须经初始化后才能被使用.当一个对象被创建时,实例变量在分配内存空间时按程序员指定的初始化值赋值,否则系统将按下列默认值进行初始化: 数据类型 初始值 byte 0 s ...
- 使用Axure RP设计Android界面原型
转至@徐州瑞步科技(http://www.cnblogs.com/brooks-dotnet/archive/2013/06/05/3119923.html) 资源地址:http://pan.baid ...
- 第一次spring冲刺第3、4天
11月14至15日 因为忙于项目的谈论与探究,以及周末的活动变动,使得博客没有时间提交上去,这里补交. 这两天,主要是应对于市场的探究做谈论,我们主要面对什么类型的客户,以及他们最需要的是什么等话题做 ...
- js中的let\var\const
在JavaScript中有三种声明变量的方式:var.let.const.下文给大家介绍js中三种定义变量的方式const, var, let的区别. 1.const定义的变量不可以修改,而且必须初始 ...
- 解决nginx+uWSGI部署Django时遇到的static文件404的问题
昨天是利用Django自带的runserver部署的服务器,但是由于runserver比较不稳定,因此决定采用uWSGI+nginx进行部署. 昨天已经安装好了uwsgi和nginx,使用该指令打开8 ...