题目链接

题意:给出一棵树,\(1\) 号点为根,边上有边权。

每个点有两个参数 \(p_i,q_i\)

如果你想从 \(i\) 号点到与其距离为 \(d\) 的 \(j\) 号点,那么你需花费 \(d \times p_i+q_i\)。

对于每个 \(i \in [2,n]\),求出:假设你站在 \(i\) 号点,到达 \(1\) 号点的最小花费。

\(1 \leq n \leq 10^6\)

树上斜率优化

dfs 求出 \(i\) 到根节点的路径长度为 \(d_i\)。

朴素的 \(dp\) 非常容易。设 \(dp_i\) 表示到达 \(i\) 号点的最小花费。那么显然

\[dp_i=\min{dp_j+(d_i-d_j) \times p_i+q_i}
\]

假设 \(j\) 在 \(k\) 的下方,那么 \(j\) 比 \(k\) 更优当且仅当:

\[dp_j+(d_i-d_j) \times p_i+q_i<dp_k+(d_i-d_k) \times p_i+q_i
\]
\[dp_j-d_j \times p_i<dp_k-d_k \times p_i
\]
\[dp_j-dp_k<(d_j-d_k) \times p_i
\]
\[\frac{dp_j-dp_k}{d_j-d_k}<p_i
\]

开个队列维护 \(i\) 的祖先的点组成的下凸包,然后在队列里二分斜率就可以了。

/*
Contest: -
Problem: P3994
Author: tzc_wk
Time: 2020.5.29
*/
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define giveup(...) return printf(__VA_ARGS__),0;
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define fillsmall(a) memset(a,0xcf,sizeof(a))
#define mask(a) (1ll<<(a))
#define maskx(a,x) ((a)<<(x))
#define _bit(a,x) (((a)>>(x))&1)
#define _sz(a) ((int)(a).size())
#define filei(a) freopen(a,"r",stdin);
#define fileo(a) freopen(a,"w",stdout);
#define fileio(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#define put(x) putchar(x)
#define eoln put('\n')
#define space put(' ')
#define y1 y1010101010101
#define y0 y0101010101010
#define int long long
typedef pair<int,int> pii;
inline int read(){
int x=0,neg=1;char c=getchar();
while(!isdigit(c)){
if(c=='-') neg=-1;
c=getchar();
}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x*neg;
}
inline int qpow(int x,int e,int _MOD){
int ans=1;
while(e){
if(e&1) ans=ans*x%_MOD;
x=x*x%_MOD;
e>>=1;
}
return ans;
}
int n=read();
vector<pii> g[1000005];
int p[1000005],q[1000005],dep[1000005],dp[1000005];
int dq[1000005],hd=1,tl=0;
inline double sl(int j,int k){
return 1.0*(dp[k]-dp[j])/(dep[k]-dep[j]);
}
inline int bsearch(double slo){
if(hd==tl) return dq[hd];
int l=hd,r=tl-1,ans=tl;
while(l<=r){
int mid=(l+r)>>1;
if(sl(dq[mid],dq[mid+1])>=slo) ans=mid,r=mid-1;
else l=mid+1;
}
return dq[ans];
}
inline void dfs(int x){
int y=bsearch(p[x]);
int curhd=hd,curtl=tl;
dp[x]=dp[y]+(dep[x]-dep[y])*p[x]+q[x];
while(hd<tl&&sl(dq[tl],dq[tl-1])>sl(dq[tl],x)) tl--;
int curq=dq[++tl];
dq[tl]=x;
foreach(it,g[x]){
int z=it->first,s=it->second;
dep[z]=dep[x]+s;
dfs(z);
}
hd=curhd,dq[tl]=curq,tl=curtl;
}
signed main(){
fz(i,2,n){
int f=read(),s=read();
p[i]=read(),q[i]=read();
g[f].push_back({i,s});
}
dfs(1);
fz(i,2,n) cout<<dp[i]<<endl;
return 0;
}

洛谷 P3994 高速公路(斜率优化)的更多相关文章

  1. 洛谷 P3994 高速公路

    https://www.luogu.org/problemnew/show/P3994 设dp[i] 表示第i个城市到根节点的最小花费 dp[i]=min{ (dis[i]-dis[j])*P[i]+ ...

  2. 【洛谷p3994】Highway 二分+斜率优化DP

    题目大意:给你一颗$n$个点的有根树,相邻两个点之间有距离,我们可以从$x$乘车到$x$的祖先,费用为$dis\times P[x]+Q[x]$,问你除根以外每个点到根的最小花费. 数据范围:$n≤1 ...

  3. 洛谷P3994 Highway(树形DP+斜率优化+可持久化线段树/二分)

    有点类似NOI2014购票 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ 这个显然是可以斜率优化的... $\frac {f(j)-f(k)}{dep_j ...

  4. Lightning Conductor 洛谷P3515 决策单调性优化DP

    遇见的第一道决策单调性优化DP,虽然看了题解,但是新技能√,很开森. 先%FlashHu大佬,反正我是看了他的题解和精美的配图才明白的,%%%巨佬. 废话不多说,看题: 题目大意 已知一个长度为n的序 ...

  5. Guard Duty (medium) Codeforces - 958E2 || (bzoj 2151||洛谷P1792) 种树 || 编译优化

    https://codeforces.com/contest/958/problem/E2 首先求出N个时刻的N-1个间隔长度,问题就相当于在这些间隔中选K个数,相邻两个不能同时选,要求和最小 方法1 ...

  6. 洛谷P2221 高速公路【线段树】

    题目:https://www.luogu.org/problemnew/show/P2221 题意:有n个节点排成一条链,相邻节点之间有一条路. C u v val表示从u到v的路径上的每条边权值都加 ...

  7. 斜率优化DP学习笔记

    先摆上学习的文章: orzzz:斜率优化dp学习 Accept:斜率优化DP 感谢dalao们的讲解,还是十分清晰的 斜率优化$DP$的本质是,通过转移的一些性质,避免枚举地得到最优转移 经典题:HD ...

  8. 洛谷P1710 地铁涨价

    P1710 地铁涨价 51通过 339提交 题目提供者洛谷OnlineJudge 标签O2优化云端评测2 难度提高+/省选- 提交  讨论  题解 最新讨论 求教:为什么只有40分 数组大小一定要开够 ...

  9. 洛谷 P5663 加工零件

    题目传送门 解题思路: 最暴力的做法: bfs模拟,每次将一个阶段的所有点拿出来,将其所有直连的点都放进队列,知道本阶段结束,最后看1号点会不会在最后一个阶段被放入队列.(洛谷数据40分) 优化了一下 ...

随机推荐

  1. WSL (Windows Subsystem for Linux)

    WSL (Windows Subsystem for Linux) :适用于 Linux 的 Windows 子系统. References Install WSL with a single com ...

  2. MySQL:提高笔记-4

    MySQL:提高笔记-4 学完基础的语法后,进一步对 MySQL 进行学习,前几篇为: MySQL:提高笔记-1 MySQL:提高笔记-2 MySQL:提高笔记-3 MySQL:提高笔记-4,本文 说 ...

  3. Scrum Meeting 0605

    零.说明 日期:2021-6-5 任务:简要汇报两日内已完成任务,计划后两日完成任务 一.进度情况 组员 负责 两日内已完成的任务 后两日计划完成的任务 困难 qsy PM&前端 暂无 重新设 ...

  4. 基于docker-compose搭建sonarqube代码质量检测平台

    一.需求 在我们开发的过程中,难免有时候代码写的不规范,或存在一些静态的bug问题,这个时候一个良好的代码检查工具就很有必要,而sonarqube正好可以满足整个要求. 二. docker-compo ...

  5. SDIO总线协议

    SDIO采用HOST-DEVICE模式,所有通信都由HOST端发命令,DEVICE设备只要解析HOST命令就可与HOST进行通信. SDIO总线的几根线: 1.  CLK信号:HOST给DEVICE的 ...

  6. cadence 技巧

    pcb中如何选中完整的一条网络? 1 edit  properties  右边 find nets 2 cadence 选中不同的网络高亮 display--->assign color在opt ...

  7. 疯狂Java基础Day2

    巩固Java流程控制的学习... 一.用户交互Scanner 通过Scanner类获取用户的输入 import java.util.Scanner; public class Demo1 { publ ...

  8. vscode插件集合整理

    针对PEPE8进行代码规范提示,安装flake8之后写代码的时候编辑器就会提示哪里出错,代码格式不规范也会提示,具体安装方式如下: 1.pip install flake8 2.安装flake8成功后 ...

  9. 最近公共祖先 牛客网 程序员面试金典 C++ Python

    最近公共祖先 牛客网 程序员面试金典 C++ Python 题目描述 有一棵无穷大的满二叉树,其结点按根结点一层一层地从左往右依次编号,根结点编号为1.现在有两个结点a,b.请设计一个算法,求出a和b ...

  10. jacoco-统计代码覆盖率并生成报告

    一.概述: 作为一个合格的测试人员,保证产品的软件质量是其工作首要目标,为了这个目标,测试人员常常会通过很多手段或工具来加以保证,覆盖率就是其中一环比较重要的环节. 通常我们会将测试覆盖率分为两个部分 ...