UOJ #7 NOI2014购票(点分治+cdq分治+斜率优化+动态规划)
重写一遍很久以前写过的题。
考虑链上的问题。容易想到设f[i]为i到1的最少购票费用,转移有f[i]=min{f[j]+(dep[i]-dep[j])*p[i]+q[i]} (dep[i]-dep[j]<=l[i])。套路的考虑若j转移优于k(dep[j]>dep[k]),则f[j]-dep[j]*p[i]<f[k]-dep[k]*p[i],f[j]-f[k]<(dep[j]-dep[k])*p[i],(f[j]-f[k])/(dep[j]-dep[k])<p[i]。若没有l[]的限制,对(dep[],f[])维护一个下凸壳即可。加入l[]的限制后,考虑使用cdq分治,右侧按dep[]-l[]从大到小排序,更新点时将新增的可以用来更新的点加入凸壳,并在凸壳上二分。
拓展到树上,通过点分治实现一个树上cdq即可,同理要先处理靠近根的部分。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 200010
#define int long long
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,p[N],t,fa[N],w[N],v[N],lim[N],deep[N],f[N],size[N],q[N],u[N],cnt2;
bool flag[N];
struct data{int to,nxt,len;
}edge[N<<1];
void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}
void dfs(int k)
{
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=fa[k])
{
deep[edge[i].to]=deep[k]+edge[i].len;
dfs(edge[i].to);
}
}
void make(int k,int from)
{
size[k]=1;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from&&!flag[edge[i].to])
{
make(edge[i].to,k);
size[k]+=size[edge[i].to];
}
}
int findroot(int k,int from,int s)
{
int mx=0;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from&&!flag[edge[i].to]&&size[edge[i].to]>size[mx]) mx=edge[i].to;
if ((size[mx]<<1)>s) return findroot(mx,k,s);
else return k;
}
void build(int k,int from,int *id,int &cnt)
{
id[++cnt]=k;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from&&!flag[edge[i].to]&&deep[edge[i].to]<deep[k]) build(edge[i].to,k,id,cnt);
}
long double slope(int x,int y){return (long double)(f[x]-f[y])/(deep[x]-deep[y]);}
void get(int k,int from)
{
u[++cnt2]=k;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from&&!flag[edge[i].to]) get(edge[i].to,k);
}
bool cmp(const int&a,const int&b)
{
return deep[a]-lim[a]>deep[b]-lim[b];
}
void solve(int k)
{
make(k,k);k=findroot(k,k,size[k]);flag[k]=1;
int id[N],cnt;id[cnt=1]=k;
for (int i=p[k];i;i=edge[i].nxt)
if (!flag[edge[i].to]&&deep[edge[i].to]<deep[k])
{
build(edge[i].to,edge[i].to,id,cnt);
solve(edge[i].to);
}
for (int i=2;i<=cnt;i++) if (deep[k]-deep[id[i]]<=lim[k]) f[k]=min(f[k],f[id[i]]+w[k]*(deep[k]-deep[id[i]])+v[k]);
cnt2=0;
for (int i=p[k];i;i=edge[i].nxt)
if (!flag[edge[i].to]) get(edge[i].to,edge[i].to);
sort(u+1,u+cnt2+1,cmp);
int t=0,tail=0;
for (int i=1;i<=cnt2;i++)
{
while (t<cnt&&deep[id[t+1]]>=deep[u[i]]-lim[u[i]])
{
while (tail>1&&slope(id[t+1],q[tail])>slope(q[tail],q[tail-1])) tail--;
q[++tail]=id[++t];
}
if (tail)
{
int l=1,r=tail-1,ans=tail;
while (l<=r)
{
int mid=l+r>>1;
if (slope(q[mid+1],q[mid])<w[u[i]]) ans=mid,r=mid-1;
else l=mid+1;
}
f[u[i]]=min(f[u[i]],f[q[ans]]+w[u[i]]*(deep[u[i]]-deep[q[ans]])+v[u[i]]);
}
}
cnt=0;
for (int i=p[k];i;i=edge[i].nxt)
if (!flag[edge[i].to]) solve(edge[i].to);
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read();read();
for (int i=2;i<=n;i++)
{
fa[i]=read();
addedge(fa[i],i,read());
addedge(i,fa[i],0);
w[i]=read(),v[i]=read(),lim[i]=read();
}
dfs(1);
memset(f,60,sizeof(f));f[1]=0;
solve(1);
for (int i=2;i<=n;i++) printf(LL,f[i]);
return 0;
}
UOJ #7 NOI2014购票(点分治+cdq分治+斜率优化+动态规划)的更多相关文章
- [BZOJ3672][UOJ#7][NOI2014]购票
[BZOJ3672][UOJ#7][NOI2014]购票 试题描述 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. ...
- 【BZOJ3672】【NOI2014】购票(线段树,斜率优化,动态规划)
[BZOJ3672][NOI2014]购票(线段树,斜率优化,动态规划) 题解 首先考虑\(dp\)的方程,设\(f[i]\)表示\(i\)的最优值 很明显的转移\(f[i]=min(f[j]+(de ...
- UOJ#7 NOI2014 购票 点分治+凸包二分 斜率优化DP
[NOI2014]购票 链接:http://uoj.ac/problem/7 因为太麻烦了,而且暴露了我很多学习不扎实的问题,所以记录一下具体做法. 主要算法:点分治+凸包优化斜率DP. 因为$q_i ...
- BZOJ3672: [Noi2014]购票【CDQ分治】【点分治】【斜率优化DP】
Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的 ...
- [BZOJ3672][Noi2014]购票 斜率优化+点分治+cdq分治
3672: [Noi2014]购票 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 1749 Solved: 885[Submit][Status][ ...
- 【uoj#244】[UER #7]短路 CDQ分治+斜率优化dp
题目描述 给出 $(2n+1)\times (2n+1)$ 个点,点 $(i,j)$ 的权值为 $a[max(|i-n-1|,|j-n-1|)]$ ,找一条从 $(1,1)$ 走到 $(2n+1,2n ...
- UOJ 7 NOI2014 购票
题意:给一棵树计算一下各个点在距离限制下以一定的费用公式通过不停地到祖先最后到达一号点的最小花费. 第一种做法:线段树维护带修凸壳.显然的,这个公式计算是p*x+q 所以肯定和斜率有关系.然后这题的d ...
- NOI 2007 货币兑换Cash (bzoj 1492) - 斜率优化 - 动态规划 - CDQ分治
Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个 ...
- [bzoj] 3263 陌上花开 洛谷 P3810 三维偏序|| CDQ分治 && CDQ分治讲解
原题 定义一个点比另一个点大为当且仅当这个点的三个值分别大于等于另一个点的三个值.每比一个点大就为加一等级,求每个等级的点的数量. 显然的三维偏序问题,CDQ的板子题. CDQ分治: CDQ分治是一种 ...
随机推荐
- cmake 手册详解【转】
https://www.cnblogs.com/coderfenghc/tag/cmake/ CMake 手册详解(二十三) SirDigit 2012-12-16 22:03 阅读:11058 ...
- linux postgresql
- 深入理解JS中&&和||
写了这么多JS,才发现JS的语法既是属于C语系的,又与一般C语系的编程语言某些地方有很大区别,其中&&和||就是其中一例. C语系中的&&和|| C语系的&&a ...
- SQLServer 拼接列
想把表里modified_by和source这两列拼接成一行
- 原理分析dubbo分布式应用中使用zipkin做链路追踪(转)
作者:@nele本文为作者原创,转载请注明出处:https://www.cnblogs.com/nele/p/10171794.html 目录 zipkin是什么为什么使用Zipkinzipkin架构 ...
- Android 打开相册拍照选择多张图片显示
添加依赖: compile 'me.iwf.photopicker:PhotoPicker:0.1.8' compile 'com.jaeger.ninegridimageview:library:1 ...
- Python之Pandas绘图,设置显示中文问题
# -*- coding: utf-8 -*- # author:baoshan import pandas as pd import matplotlib.pyplot as plt plt.rcP ...
- VPB编译日志2
1>------ 已启动全部重新生成: 项目: ZERO_CHECK, 配置: Debug x64 ------1> Checking Build System1> CMake do ...
- AD 常用策略-修改本地管理员密码,禁用非administrator帐户,删除非administrator帐户
这个是用启动脚本实现的. 我放在计算机策略下了. 另存为VBS格式即可 修改第三行“123qwe!@#”,引号中的就是你的新密码. 一:禁用非administrator帐户 strComputer = ...
- 内层元素设置position:relative后父元素overflow:hidden overflow:scroll失效 解决方法
内层元素设置position:relative后父元素overflow:hidden overflow:scroll 都失效 解决方法:在position:relative的外层父容器加positio ...