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 ...
随机推荐
- 1. md5 collision(50)
md5 collision(50) ------南京邮电大学ctf: http://chinalover.sinaapp.com/web19/ 发现了一串代码 <?php $md51 ...
- mysql给id生成uuid
mysql中id一般都设为uuid,除了我们在后台用到的uuid利用jpa注解来生成外,其实在mysql中直接也可以生成 直接上代码: 1.mysql中直接使用uuid()函数,可以生成一个随机的uu ...
- C++11/14的新特性——更简洁
新的字符串表示方式——原生字符串(Raw String Literals) C/C++中提供了字符串,字符串的转义序列,给输出带来了很多不变,如果需要原生义的时候,需要反转义,比较麻烦. C++提 ...
- linux文件重命名
rename 命令用字符串替换的方式批量改变文件名. 语法 rename(参数) 参数 原字符串:将文件名需要替换的字符串: 目标字符串:将文件名中含有的原字符替换成目标字符串: 文件:指定要改变文件 ...
- [Swift]LeetCode1078. Bigram 分词 | Occurrences After Bigram
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- 已知单链表的数据元素为整型数且递增有序,L为单链表的哨兵指针。编写算法将表中值大于X小于Y的所有结点的顺序逆置。(C语言)
对此题目的完整示例可直接运行代码如下: #include <stdio.h> #include <stdlib.h> typedef struct LNode{ int dat ...
- css 文本溢出时显示省略号
.text-ellipsis { width:100px; height:60px; overflow: hidden;//隐藏滚动条 text-overflow:ellipsis; white-sp ...
- 【bzoj4567】[Scoi2016]背单词
4567: [Scoi2016]背单词 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1123 Solved: 476[Submit][Status][ ...
- 长春理工大学第十四届程序设计竞赛(重现赛)F.Successione di Fixoracci
链接:https://ac.nowcoder.com/acm/contest/912/F 题意: 动态规划(Dynamic programming,简称dp)是一种通过把原问题分解为相对简单的子问题的 ...
- 最长回文子串--轻松理解Manacher算法
最长回文子串这个问题的Manacher算法,看了很多博客,好不容易理解了,做一下记录. 这个算法的核心就是:将已经查询过的子字符串的最右端下标保存下来,在计算下标为i的回文字符串时,不需要从左右相邻的 ...