$NOI2014$ 购票(斜率优化 点分治)
\(NOI2014\)购票
哇终于可以碰电脑了赶快切些火题找找感觉。
拿到这道题的时候发现简单的斜率优化推一推可以秒掉平方做法,然后一条链也可以做。
然后呢。。。
卧槽这个在一棵树上怎么办啊。
大力\(YY\)了一个数据结构维护区间凸壳的东西,然而我感觉这东西好恶心啊我不会啊。。。
明明就是因为懒
然后翻了一波题解发现可以用点分治,然而都讲得非常不清楚。。。。
看了好久才看懂怎么做吧。。。我这里详细地记录一下。。
详细是不存在的这辈子的不存在的
总体思想是,每次点分治的时候有两个关键点,一个是分治重心,一个是当前子树的根节点。
每次先将含有当前子树根节点的那个分治子树加上分治重心作为一个全新的子树先递归处理
然后把分治中心到当前根节点的路径上的点抠出来,用这些点来更新其他不包含根节点的分治子树。
这个更新是可以统一处理的,具体操作就是把所有点抠出来按照可到达的最浅点从深到浅排个序
也就是斜率计算中的\(x\)
然后从分治重心一步步向上跳父亲加入单调栈,得到用于更新答案的单调栈
因为斜率不单调所以我们要在单调栈上二分
然后再继续递归不包含根节点的分治子树就完成啦。
这样做相当于从浅到深依次分治,依次把\(DP\)值确定好了。
方便理解的话注意一下这棵树是不需要建反边的。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<queue>
#include<map>
#include<vector>
using namespace std;
#define N 201000
#define EPS 1e-7
#define ll long long
#define RG register
#define inf 1e18+1
inline ll read(){
RG ll x=0,o=1; RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') o=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=((x<<3)+(x<<1))+ch-'0',ch=getchar();
return x*o;
}
int n,first[N],top,siz[N],vis[N],tmp[N],tot,Max,Sz,Rt,fa[N],Q[N],cnt;
ll dis[N],lim[N],p[N],q[N],f[N];
struct mona { int nxt,en; } s[N<<1];
inline void Insert(int x,int y) { s[++top]=(mona) { first[x],y },first[x]=top; }
inline void Getroot(int k){
siz[k]=1; int Maxn=0;
for(RG int i=first[k];i;i=s[i].nxt){
int en=s[i].en; if(vis[en]) continue ;
Getroot(en),Maxn=max(Maxn,siz[en]),siz[k]+=siz[en];
} Maxn=max(Maxn,Sz-siz[k]); if(Max>=Maxn) Max=Maxn,Rt=k;
}
inline void Getdis(int k){
tmp[++tot]=k;
for(RG int i=first[k];i;i=s[i].nxt)
if(!vis[s[i].en]) Getdis(s[i].en);
}
inline bool cmp(const int &x,const int &y) { return dis[x]-lim[x]>dis[y]-lim[y]; }
inline double Slope(const int &i,const int &j){
if(dis[i]==dis[j]) return f[i]<f[j]?inf:-inf;
return (1.0*f[i]-f[j])/(1.0*dis[i]-dis[j]);
}
inline void Add(int i){
while(cnt>1&&Slope(Q[cnt],Q[cnt-1])<=Slope(i,Q[cnt-1])) --cnt;
Q[++cnt]=i;
}
inline int Binary(int cst){
int l=2,r=cnt,ans=1;
while(l<=r){
int mid=l+r>>1;
if(Slope(Q[mid],Q[mid-1])>=cst) ans=mid,l=mid+1;
else r=mid-1;
} return Q[ans];
}
inline void Divide(int k,int Siz){
if(Siz==1) return ; Sz=Siz,Max=1e9,Getroot(k); int Cr=Rt;
for(RG int i=first[Cr];i;i=s[i].nxt) vis[s[i].en]=1;
Divide(k,Siz-siz[Cr]+1),tot=0;
for(RG int i=first[Cr];i;i=s[i].nxt) Getdis(s[i].en);
sort(tmp+1,tmp+1+tot,cmp); int now=Cr; cnt=0,Add(Cr);
for(RG int i=1;i<=tot;++i){ int t=tmp[i];
if(dis[now]<dis[t]-lim[t]) continue ;
while(now!=k&&dis[fa[now]]>=dis[t]-lim[t])
now=fa[now],Add(now);
int Bes=Binary(p[t]);
f[t]=min(f[t],f[Bes]+(dis[t]-dis[Bes])*p[t]+q[t]);
} for(RG int i=first[Cr];i;i=s[i].nxt) Divide(s[i].en,siz[s[i].en]);
}
inline void Dfs(int k){
for(RG int i=first[k];i;i=s[i].nxt)
dis[s[i].en]+=dis[k],Dfs(s[i].en);
}
int main(){
n=read(),read();
for(RG int i=2;i<=n;++i)
fa[i]=read(),dis[i]=read(),Insert(fa[i],i),
p[i]=read(),q[i]=read(),lim[i]=read(),f[i]=inf;
Dfs(1),Sz=n,Divide(1,n);
for(RG int i=2;i<=n;++i) printf("%lld\n",f[i]);
}
随机推荐
- WinForm、WPF、ASP.NET窗口生命周期
https://blog.csdn.net/s_521_h/article/details/73826928
- Python Web框架本质——Python Web开发系列一
前言:了解一件事情本质的那一瞬间总能让我获得巨大的愉悦感,希望这篇文章也能帮助到您. 目的:本文主要简单介绍Web开发中三大基本功能:Socket实现.路由系统.模板引擎渲染. 进入正题. 一. 基础 ...
- 2019 年百度之星—初赛一 B题 Game
题目链接 题意:最开始可以选择任意位置,在一个坐标轴上,依次走到一个区间里面,可以选择走一步两步,求最小步数. 思路:贪心,刚开始合并区间,确定初始位置以及方向.往右走肯定到左端点,往左走先到右端点, ...
- digits 2
digits 2 震惊了== 我还交的表,发现直接输出n个n就行=== #include<bits/stdc++.h> using namespace std; ]={ ", & ...
- [CSP-S模拟测试110]题解
也许是最后一篇了. A.最大或 不错的签到题. 对于二进制位来说,高位的一个1比低位的所有1的贡献总和还要大. 显然,$r$必选,因为$r$中所有1的相对考前.那么考虑如何构造另一个数. 首先$l$和 ...
- map()函数用法
需求:已知两个列表,现在要一个列表中的元素,分别全部插入另一个列表中,新列表是[[0, 9, 1], [0, 9, 2], [0, 9, 3], [0, 9, 4], [0, 9, 5], [0, 9 ...
- HDU 5634 Rikka with Phi
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5634 ------------------------------------------------ ...
- mysql_DML_索引、视图
创建索引的语法格式:– 创建普通索引:• create index 索引名称 on 表名(列)• alter table 表名 add index 索引名称 (列)– 创建唯一索引:• create ...
- Django 的工作流程和基本内容
1.一个基本的Django请求流程 我们先开始写一个基本的请求.这个请求的获取和处理,是使用 urls.py 和 views.py 处理的.我们使用命令 python manage.py runser ...
- MySQL 服务器性能剖析
这是<高性能 MySQL(第三版)>第三章的读书笔记. 关于服务,常见的问题有: 如何确认服务器是否发挥了最大性能 找出执行慢的语句,为何执行慢 为何在用户端发生间歇性的停顿.卡死 通过性 ...