P3994 高速公路 树形DP+斜率优化+二分
$ \color{#0066ff}{ 题目描述 }$
C国拥有一张四通八达的高速公路网树,其中有n个城市,城市之间由一共n-1条高速公路连接。除了首都1号城市,每个城市都有一家本地的客运公司,可以发车前往全国各地,有若干条高速公路连向其他城市,这是一个树型结构,1号城市(首都)为根。假设有一个人要从i号城市坐车出发前往j号城市,那么他要花费Pi*(i城市到j城市的距离)+Qi元。由于距离首都越远,国家的监管就越松,所以距离首都越远,客运公司的Pi(单位距离价格)越大,形式化的说,如果把高速路网看成一棵以首都为根的有根树,i号城市是j号城市的某个祖先,那么一定存在Pi<=Pj。
大宁成为了国家统计局的调查人员,他需要对现在的高速路网进行一次调查,了解从其他每一个城市到达首都1号城市所花费的金钱(路径必须是简单路径)。
因为有非常多转车(或不转车)的抵达首都的方法,所以人工计算这个结果是十分复杂的。大宁非常的懒,所以请你编写一个程序解决它。
\(\color{#0066ff}{输入格式}\)
第 1 行包含1个非负整数 n,表示城市的个数。
第 2 到 n 行,每行描述一个除首都之外的城市。其中第 i 行包含4 个非负整数 Fi,Si,Pi,Qi,分别表示 i号城市的父亲城市,它到父亲城市高速公路的长度,以及乘车价格的两个参数。
\(\color{#0066ff}{输出格式}\)
输出包含 n-1 行,每行包含一个整数。
其中第 i 行表示从 i+1号城市 出发,到达首都最少的乘车费用。
\(\color{#0066ff}{输入样例}\)
6
1 9 3 0
1 17 1 9
1 1 1 6
4 13 2 15
4 9 2 4
\(\color{#0066ff}{输出样例}\)
27
26
7
43
24
\(\color{#0066ff}{数据范围与提示}\)
对于前40%的数据1<=n<=1000。
对于另外20%的数据 满足从第i(i≠1)个城市出发的高速公路连向第i-1个城市。
对于所有的数据1<=n<=1000000,0<=Pi,Qi<=231-1,保证结果不会大于263-1。
\(\color{#0066ff}{题解}\)
不难想到DP,设\(f[i]\)为从i到根的答案,转移也很好想
\(f[i] =min(f[i],f[j]+(dis[i])-dis[j])*p[i]+q[i])\)
但是这样转移是\(O(n^2)\)的,显然过不了啊
我们考虑斜率优化
如果x比y优秀,即\(f[x]+(dis[i]-dis[x])*p[i]+q[i]<f[y]+(dis[i]-dis[y])*p[i]+q[i]\)
化简之后是\(p[i]<\frac{f[x]-f[y]}{dis[x]-dis[y]}\)
这样就能斜率优化了,用单调队列维护一个下凸包
但是,这是优化的树形DP啊, 在一棵子树内的决策会影响到另一棵子树!
我们考虑每次转移单调队列的变化,看能不能搞点什么
可以发现,每次head仅仅是移动,其中元素是不变的(祖先链不变)
tail呢?每次移动后只会修改一个值!
所以我们可以记录一下每个点的head和tail,还有修改的元素位置和编号,这样就可以快速回溯
但是这样每个点会入队多次,上界依然是\(O(n^2)\)
又因为元素是不变的,所以,我们考虑二分来优化这个过程,每次二分两次,找到转移点和修改点即可
#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int maxn = 1e6 + 100;
LL dep[maxn], f[maxn];
LL p[maxn], q[maxn];
int st[maxn], head, tail;
int n;
struct node {
int to, dis;
node *nxt;
node(int to = 0, int dis = 0, node *nxt = NULL): to(to), dis(dis), nxt(nxt) {}
}*h[maxn];
void add(int from, int to, int dis) { h[from] = new node(to, dis, h[from]); }
void dfs(int x) { for(node *i = h[x]; i; i = i->nxt) dep[i->to] = dep[x] + i->dis, dfs(i->to); }
double K(int x, int y) { return (double)(f[x] - f[y]) / (double)(dep[x] - dep[y]); }
void work(int x) {
int nowhead = head, nowtail = tail;
int l = head, r = tail - 1, ans = -1;
while(l <= r) {
int mid = (l + r) >> 1;
if(p[x] <= K(st[mid], st[mid + 1])) ans = mid, r = mid - 1;
else l = mid + 1;
}
if(~ans) head = ans;
else head = tail;
f[x] = f[st[head]] + (dep[x] - dep[st[head]]) * p[x] + q[x];
l = head, r = tail - 1, ans = -1;
while(l <= r) {
int mid = (l + r) >> 1;
if(K(st[mid], st[mid + 1]) < K(st[mid + 1], x)) ans = mid, l = mid + 1;
else r = mid - 1;
}
if(~ans) tail = ans + 1;
else tail = head;
int now = st[++tail];
st[tail] = x;
for(node *i = h[x]; i; i = i->nxt) work(i->to);
head = nowhead, st[tail] = now, tail = nowtail;
}
int main() {
n = in();
int x, y;
for(int i = 2; i <= n; i++) {
x = in(), y = in();
add(x, i, y);
p[i] = in(), q[i] = in();
}
dfs(1);
for(node *i = h[1]; i; i = i->nxt) st[head = tail = 1] = 1, work(i->to);
for(int i = 2; i <= n; i++) printf("%lld\n", f[i]);
return 0;
}
P3994 高速公路 树形DP+斜率优化+二分的更多相关文章
- 洛谷P3994 Highway(树形DP+斜率优化+可持久化线段树/二分)
有点类似NOI2014购票 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ 这个显然是可以斜率优化的... $\frac {f(j)-f(k)}{dep_j ...
- Codeforces 1179D 树形DP 斜率优化
题意:给你一颗树,你可以在树上添加一条边,问添加一条边之后的简单路径最多有多少条?简单路径是指路径中的点只没有重复. 思路:添加一条边之后,树变成了基环树.容易发现,以基环上的点为根的子树的点中的简单 ...
- BZOJ2726:任务安排(DP+斜率优化+二分)
机器上有N个需要处理的任务,它们构成了一个序列.这些任务被标号为1到N,因此序列的排列为1,2,3...N.这N个任务被分成若干批,每批包含相邻的若干任务.从时刻0开始,这些任务被分批加工,第i个任务 ...
- bzoj3672: [Noi2014]购票(树形DP+斜率优化+可持久化凸包)
这题的加强版,多了一个$l_i$的限制,少了一个$p_i$的单调性,难了好多... 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ $\frac {f(j) ...
- DP斜率优化总结
目录 DP斜率优化总结 任务安排1 任务计划2 任务安排3 百日旅行 DP斜率优化总结 任务安排1 首先引入一道题,先\(O(N^2)\)做法:分别预处理出\(T_i,C_i\)前缀和\(t[i],c ...
- HDU 3507 [Print Article]DP斜率优化
题目大意 给定一个长度为\(n(n \leqslant 500000)\)的数列,将其分割为连续的若干份,使得 $ \sum ((\sum_{i=j}^kC_i) +M) $ 最小.其中\(C_i\) ...
- 【BZOJ-4518】征途 DP + 斜率优化
4518: [Sdoi2016]征途 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 230 Solved: 156[Submit][Status][ ...
- 【BZOJ-3437】小P的牧场 DP + 斜率优化
3437: 小P的牧场 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 705 Solved: 404[Submit][Status][Discuss ...
- 【BZOJ-1010】玩具装箱toy DP + 斜率优化
1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 8432 Solved: 3338[Submit][St ...
随机推荐
- Angular-cli新建项目目录结构详解
Angular-cli新建项目目录结构详解 在上一篇博客中我们已经通过Angular CLI命令行工具创建出来一个全新的Angular项目,要想写项目,首先我们要先搞清楚项目的目录结构是怎样的,每个文 ...
- C++深度解析教程学习笔记(4)C++中的新成员
1. 动态内存分配 (1)C++通过 new 关键字进行动态内存申请,是以类型为单位来申请空间大小的 (2)delete 关键字用于内存释放 ▲注意释放数组时要加[],否则只释放这个数组中的第 1 个 ...
- python的ftplib模块
Python中的ftplib模块 Python中默认安装的ftplib模块定义了FTP类,其中函数有限,可用来实现简单的ftp客户端,用于上传或下载文件 FTP的工作流程及基本操作可参考协议RFC95 ...
- webService调用模式比较
- redis实现发布订阅
订阅者 #!/usr/bin/env python # -*- coding:utf-8 -*- import redis r = redis.Redis(host='192.168.11.119') ...
- Windows 环境下于虚拟环境中源码安装 cx_oracle
安装前提条件: (1).安装 instantclient-basic-nt (2).安装 instantclient-sdk-nt (3).安装 Microsoft Visual C++ Compil ...
- 【FZU 2277】Change
题意 有一颗有n个节点的有根树,根节点编号时1,每个结点都有一个值ai,开始的时候,所有节点的值都是0. 我们有q个操作,操作只有两种类型 1 v x k,a[v]+=x,a[v']+=x-k,a[v ...
- mysql数据库中插入表情4个字节的
这个问题,原因是UTF-8编码有可能是两个.三个.四个字节.Emoji表情或者某些特殊字符是4个字节,而Mysql的utf8编码最多3个字节,所以数据插不进去. 我的解决方案是这样的 1.在mysql ...
- ubuntu下不用eclipse开发cocos2d-x(命令行)
之前在ubuntu下通过eclipse搭建开发cocos2d-x的环境,但是由于eclipse界面在ubuntu显得很丑,在里面写代码,完全没有感觉,后来我转到了win7上通过vs2010和eclip ...
- 【转】LVS负载均衡之session解决方案 持久连接
原文地址:http://minux.blog.51cto.com/8994862/1744761 1. 持久连接是什么? 1.1 在LVS中,持久连接是为了用来保证当来自同一个用户的请求时能够定位到同 ...