【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. day5 面向对象

    面向对象的特征 封装(encapsulation) 继承(inheritance) 多态(polymorphism) 开发的过程:其实就是不断的创建对象,使用对象,指挥对象做事情. 设计的过程:其实就 ...

  2. PHP注释-----PHPDOC

    用过IDE或看过其他源码的小伙伴们应该都见过类似下面这样的注释   /** * 递归获取所有游戏分类 * @param int $id * @return array */ 看得多了就大概知道了一些规 ...

  3. Guid string 转换

    System.Guid.NewGuid().ToString(); //GUID带-分割// db1b98e9-6f93-41aa-84f8-5eb773e93d67System.Guid.NewGu ...

  4. CentOS6下用yum升级系统最新内核版本

    首先当你决定升级内核时,要想清楚为什么升级内核,因为升级内核会带来很多麻烦.所以这种事情能避免就避免 导入 Public Key rpm --import https://www.elrepo.org ...

  5. Linux之常用命令简析

    ls cd mkdir rmdir touch ln cp rm mv 1.ls   显示当前目录下的文件及文件夹(不显示隐藏的) -l   显示详细信息 --all  显示隐藏的文件及文件夹(就是显 ...

  6. lightoj1010【规律】

    思路: 根据案例的规律其实已经猜的差不多了,answer=n*m/2; 有一条边是1的情况,也很好判断,answer=n*m; 就是有一条边是2的时候比较隐秘:是连续2*2一块可以填,然后2*2不填, ...

  7. UIPI VS与Win7 共舞:用户界面特权隔离

    http://tech.it168.com/a2009/0924/737/000000737968.shtml [IT168 专稿]在上文中,我们介绍了操作系统服务的Session 0隔离,通过Ses ...

  8. 51nod1105(二分)

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1105 题意:中文题诶- 思路:直接二分答案,再通过二分找有多少 ...

  9. 洛谷P3110 [USACO14DEC]驮运Piggy Back

    P3110 [USACO14DEC]驮运Piggy Back 题目描述 贝西和她的妹妹艾尔斯白天在不同的地方吃草,而在晚上他们都想回到谷仓休息.聪明的牛仔,他们想出了一个计划,以尽量减少他们在步行时花 ...

  10. HTTP之间的区别和特性

    一. Http 简介 Http,学名超文本传输协议 它理解起来并不复杂,平时并不起眼,但经常使用; 前后端交互,多数依赖于http协议,重要性看个人理解,我不敢使用个人认为不掌握的技术; 二. HTT ...