【NOI2014】购票

链接:http://uoj.ac/problem/7

因为太麻烦了,而且暴露了我很多学习不扎实的问题,所以记录一下具体做法。

主要算法:点分治+凸包优化斜率DP。

因为$q_i$不单调,所以需要在凸包上二分求最优解。

因为有$L_i$的限制,并且删除凸包左边的点会导致一些问题,所以就改变枚举顺序(倒着加入祖先链),使问题变成不用删点。因此直接套用凸包二分求解的模板。

大致流程:

Tree_Divide_conquer(fa[x]).//先求出祖先链的Dp值
Get_all_son();//将除了x父亲那一端,该重心层的点都放A中
sort(A+,A++now);//按dis_i-L_i递减排序
for(int i=,t=fa[x];i<=now;i++)
{
for(;t!=fa[up]&&dis[t]>=dis[A[i]]-l[A[i]];t=fa[t])//up记录该重心层深度最浅的点的父亲
ADD(t);
UPD(A[i]);//在凸包上二分
}
Tree_Divide_conquer(....)//分治其他子树

Code:

#include<cstdio>
#include<algorithm> typedef long long ll;
template<class T>
inline void read(T&x)
{
x=;bool f=;char c=getchar();
while((c<''||c>'')&&c!='-')c=getchar(); if(c=='-')f=,c=getchar();
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
x=f?-x:x;
}
const int MAXN();
const ll INF(0x7fffffffffffffff);
struct Node{int nd,nx;}bot[MAXN<<];int tot,first[MAXN];
void add(int a,int b){bot[++tot]=(Node){b,first[a]},first[a]=tot;}
int n,t,fa[MAXN],p[MAXN];ll f[MAXN],l[MAXN],dis[MAXN],s[MAXN],q[MAXN],last[MAXN];
//===================================var
int st[MAXN],tp;
ll sum(int x,int y)
{
return f[y]+(dis[x]-dis[y])*(ll)p[x]+q[x];
}
double slope(int u,int v)
{
return 1.0*(f[u]-f[v])/(dis[u]-dis[v]);
}
void UPD(int x)
{
int li=,ri=tp-,mid,Ans=tp;
for(;li<=ri;)
{
mid=(li+ri)>>;
if(slope(st[mid+],st[mid])<=p[x])ri=mid-,Ans=mid;else li=mid+;
}
if(Ans<=tp&&tp)
{
ll tmp=sum(x,st[Ans]);
if(f[x]>=tmp)f[x]=tmp,last[x]=st[Ans];
}
}
void ADD(int x)
{
while(tp>&&slope(st[tp-],st[tp])<slope(st[tp],x))
tp--;
st[++tp]=x;
}
//===================================斜率优化/凸包
int size[MAXN],big[MAXN],col[MAXN],root[MAXN],flag[MAXN],all;
void Get_size(int x,int f)
{
size[x]=;big[x]=;
for(int v=first[x];v;v=bot[v].nx)
if(bot[v].nd!=f&&flag[bot[v].nd]==)
{
Get_size(bot[v].nd,x);
size[x]+=size[bot[v].nd];
big[x]=std::max(big[x],size[bot[v].nd]);
}
}
void Get_root(int x,int f)
{
col[x]=col[f];
for(int v=first[x];v;v=bot[v].nx)
if(bot[v].nd!=f&&flag[bot[v].nd]==)
Get_root(bot[v].nd,x);
big[x]=std::max(big[x],all-size[x]);
if(big[x]*<=all)root[col[x]]=x;
}
int A[MAXN],now;
bool cmp(int a,int b){return dis[a]-l[a]>dis[b]-l[b];}
void Get_ans(int x,int f)
{
for(int v=first[x];v;v=bot[v].nx)
if(bot[v].nd!=f&&flag[bot[v].nd]==)
Get_ans(bot[v].nd,x);
A[++now]=x;
}
void Tree_Dive_And_Conquer(int x)
{
int up=x;while(!flag[up])up=fa[up];
flag[x]=;
for(int v=first[x];v;v=bot[v].nx)
if(!flag[bot[v].nd])
{
col[x]=bot[v].nd;
Get_size(bot[v].nd,x);all=size[bot[v].nd];
Get_root(bot[v].nd,x);
}
if(!flag[fa[x]])Tree_Dive_And_Conquer(root[fa[x]]);
A[now=]=x;
for(int v=first[x];v;v=bot[v].nx)
if(!flag[bot[v].nd])Get_ans(bot[v].nd,x);
std::sort(A+,A++now,cmp);
tp=;
for(int i=,t=fa[x];i<=now;i++)
{
for(;t!=fa[up]&&dis[t]>=dis[A[i]]-l[A[i]];t=fa[t])
ADD(t);
UPD(A[i]);
}
for(int v=first[x];v;v=bot[v].nx)
if(!flag[bot[v].nd])Tree_Dive_And_Conquer(root[bot[v].nd]);
}//O(nlog^2n)
void run()
{
Get_size(,);
for(int i=;i<=n;i++)
{
big[i]=std::max(big[i],n-size[i]);
if(big[i]*<=n)root[]=i;
}
flag[]=;Tree_Dive_And_Conquer(root[]);
}
//===================================点分治
int main()
{
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
read(n);read(t);
for(int i=;i<=n;i++)
{
read(fa[i]);read(s[i]);read(p[i]);read(q[i]);read(l[i]);
add(i,fa[i]);add(fa[i],i);dis[i]=dis[fa[i]]+s[i];f[i]=INF;
}
run();
for(int i=;i<=n;i++)printf("%lld\n",f[i]);
return ;
}

UOJ#7 NOI2014 购票 点分治+凸包二分 斜率优化DP的更多相关文章

  1. BZOJ3672: [Noi2014]购票【CDQ分治】【点分治】【斜率优化DP】

    Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的 ...

  2. Codeforces Round #344 (Div. 2) E. Product Sum 二分斜率优化DP

    E. Product Sum   Blake is the boss of Kris, however, this doesn't spoil their friendship. They often ...

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

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

  4. SCUT - 365 - 鹏哥的数字集合 - wqs二分 - 斜率优化dp

    https://scut.online/p/365 https://www.luogu.org/problemnew/solution/P2365 写这篇的时候还不是很明白,看一下这个东西. http ...

  5. [Noi2014]购票 斜率优化DP+可持久化凸包

    貌似网上大部分题解都是CDQ分治+点分治然后再斜率优化DP,我貌似并没有用这个方法. 这一题跟这题有点像,只不过多了一个l的限制 如果说直接跑斜率优化DP,存储整个序列的话,显然是不行的,如图所示(图 ...

  6. [BZOJ3672][UOJ#7][NOI2014]购票

    [BZOJ3672][UOJ#7][NOI2014]购票 试题描述  今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会.       ...

  7. 【bzoj3672】[Noi2014]购票 斜率优化dp+CDQ分治+树的点分治

    题目描述  给出一棵以1为根的带边权有根树,对于每个根节点以外的点$v$,如果它与其某个祖先$a$的距离$d$不超过$l_v$,则可以花费$p_vd+q_v$的代价从$v$到$a$.问从每个点到1花费 ...

  8. BZOJ_3672_ [Noi2014]购票_CDQ分治+斜率优化

    BZOJ_3672_ [Noi2014]购票_CDQ分治+斜率优化 Description  今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参 ...

  9. 【BZOJ3672】【NOI2014】购票(线段树,斜率优化,动态规划)

    [BZOJ3672][NOI2014]购票(线段树,斜率优化,动态规划) 题解 首先考虑\(dp\)的方程,设\(f[i]\)表示\(i\)的最优值 很明显的转移\(f[i]=min(f[j]+(de ...

随机推荐

  1. Centos7更新阿里yum源

    一.下载repo文件 wget http://mirrors.aliyun.com/repo/Centos-7.repo 二.备份并替换系统的repo文件 cp Centos-7.repo /etc/ ...

  2. ubuntu: 终端全屏快捷键

    ubuntu12.04终端全屏 (2012-06-08 19:49:04) 转载▼ 进入终端全屏: ctrl+alt+f1 ctrl+alt+f2 ctrl+alt+f3 ctrl+alt+f4 ct ...

  3. 伪类选择器 :nth-child(even) :nth-child(odd) :nth-of-type

    属性 描述 CSS :active 向被激活的元素添加样式. 1 :focus 向拥有键盘输入焦点的元素添加样式. 2 :hover 当鼠标悬浮在元素上方时,向元素添加样式. 1 :link 向未被访 ...

  4. poj 2769 感觉♂良好 (单调栈)

    poj 2769 感觉♂良好 (单调栈) 比尔正在研发一种关于人类情感的新数学理论.他最近致力于研究一个日子的好坏,如何影响人们对某个时期的回忆. 比尔为人的一天赋予了一个正整数值. 比尔称这个值为当 ...

  5. Mac 下nginx 环境的配置

    这个是在度娘那里学来的. 因为是使用brew所以先安装: 安装命令如下:curl -LsSf http://github.com/mxcl/homebrew/tarball/master | sudo ...

  6. Netty源码分析(七):初识ChannelPipeline

    ChannelPipeline单看名称就可以知道Channel的管道.本篇将结合它的默认实现类DefaultChannelPipeline来对它做一个简单的介绍. 示例图 上图是官方提供的Channe ...

  7. 用户唯一性验证(ajax)

    验证用户添加或者修改时用户名的唯一性: 验证时机:用户名改变时,表单提交时. 1.jsp页面:(前端) <%@ page contentType="text/html;charset= ...

  8. jQuery EasyUI/TopJUI创建日期输入框

    jQuery EasyUI/TopJUI创建日期输入框 日期时间输入框组件 HTML required:必填字段,默认为false:prompt:显示在输入框的提示性文字:pattern:日期格式 Y ...

  9. [题解](prufer)明明的烦恼

    https://www.cnblogs.com/noip/archive/2013/03/10/2952520.html 以及高精(抄 #include<iostream> #includ ...

  10. Js 文件上传后缀验证

    //img格式验证 function imgFormat(name) { //再对文件名进行截取,以取得后缀名 var namearr= name.split("."); //获取 ...