UOJ#7 NOI2014 购票 点分治+凸包二分 斜率优化DP
【NOI2014】购票
因为太麻烦了,而且暴露了我很多学习不扎实的问题,所以记录一下具体做法。
主要算法:点分治+凸包优化斜率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的更多相关文章
- BZOJ3672: [Noi2014]购票【CDQ分治】【点分治】【斜率优化DP】
Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的 ...
- 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 ...
- 【洛谷p3994】Highway 二分+斜率优化DP
题目大意:给你一颗$n$个点的有根树,相邻两个点之间有距离,我们可以从$x$乘车到$x$的祖先,费用为$dis\times P[x]+Q[x]$,问你除根以外每个点到根的最小花费. 数据范围:$n≤1 ...
- SCUT - 365 - 鹏哥的数字集合 - wqs二分 - 斜率优化dp
https://scut.online/p/365 https://www.luogu.org/problemnew/solution/P2365 写这篇的时候还不是很明白,看一下这个东西. http ...
- [Noi2014]购票 斜率优化DP+可持久化凸包
貌似网上大部分题解都是CDQ分治+点分治然后再斜率优化DP,我貌似并没有用这个方法. 这一题跟这题有点像,只不过多了一个l的限制 如果说直接跑斜率优化DP,存储整个序列的话,显然是不行的,如图所示(图 ...
- [BZOJ3672][UOJ#7][NOI2014]购票
[BZOJ3672][UOJ#7][NOI2014]购票 试题描述 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. ...
- 【bzoj3672】[Noi2014]购票 斜率优化dp+CDQ分治+树的点分治
题目描述 给出一棵以1为根的带边权有根树,对于每个根节点以外的点$v$,如果它与其某个祖先$a$的距离$d$不超过$l_v$,则可以花费$p_vd+q_v$的代价从$v$到$a$.问从每个点到1花费 ...
- BZOJ_3672_ [Noi2014]购票_CDQ分治+斜率优化
BZOJ_3672_ [Noi2014]购票_CDQ分治+斜率优化 Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参 ...
- 【BZOJ3672】【NOI2014】购票(线段树,斜率优化,动态规划)
[BZOJ3672][NOI2014]购票(线段树,斜率优化,动态规划) 题解 首先考虑\(dp\)的方程,设\(f[i]\)表示\(i\)的最优值 很明显的转移\(f[i]=min(f[j]+(de ...
随机推荐
- 微信小程序开发之tab导航栏
实现功能: 点击不同的tab导航,筛选数据 UI: js: data:{ navbar: ['半月维保', '季度维保', '半年维保',"年度维保"], //count ...
- 优酷电视剧爬虫代码实现一:下载解析视频网站页面(4)补充: Java正则表达式Matcher.group(int group)相关类解析
在Java正则表达式的相关类Matcher中,有如下几个方法: - int groupCount() - String group(int group) - int start(int group) ...
- UE4中资源加载资源的方式
在UNITY中,我们加载资源一般是通过Resources.Load(path).即可完成.该方法返回的是Object类型.如果你想要的是材质或者贴图等等,只要价格类型转换的关键字就可以了例如 as M ...
- cf706C(dp)
题目链接:http://codeforces.com/problemset/problem/706/C 题意:给出n个字符串,反转第 i 个字符串需要花费 ai,问通过反转操作将n个字符串变成升序排列 ...
- codevs2830 蓬莱山辉夜
2830 蓬莱山辉夜 题目描述 Description 在幻想乡中,蓬莱山辉夜是月球公主,居住在永远亭上,二次设定说她成天宅在家里玩电脑,亦称NEET姬一天,她要她帮忙升级月球的网络服务器,应为注 ...
- abap table control里面各种属性和事件的写法
SAP中,Table Control是在Screen中用的最广泛的控件之一了,可以实现对多行数据的编辑. 简单来说,Table Control是一组屏幕元素在Screen上的重复出现,这就是它与普通屏 ...
- vuex初使用(写的当然是最简单的应用啦)
关于vuex的简图 vuex文档:https://vuex.vuejs.org/zh-cn/installation.html 一:npm安装 npm install vuex --save 在mai ...
- [Andoird]Andoird之Log
一.Log Android中的日志工具类是 Log(android.util.Log),这个类中提供了如下几个方法来供我们打印日志. Log.v() 这个方法用于打印那些最为琐碎的,意义最小的日志信息 ...
- sublime下Docblocker插件自定义配置
1.下载安装Docblocker插件 栏目preferences-->Package Control 输入 Docblocker 搜索插件,单击安装 简单使用: 在函数头部输入: /** 按 ...
- Webservice入门简单实例
转载大神 项目目的: 程序A调用程序B中的方法C.. https://blog.csdn.net/lovebosom/article/details/51558139 ...