洛谷P2305 [NOI2014]购票 [DP,树状数组]
思路
显然是树形DP,显然是斜率优化,唯一的问题就是该怎么维护凸包。
套路1:树上斜率优化,在没有这题的路程的限制的情况下,可以维护一个单调栈,每次加入点的时候二分它会加到哪里,然后替换并记录,等从这个点回溯上来的时候再撤销。
套路2:有路程限制时,不能简单替换,因为你可能会替换掉一个下面有用的点,然后WA掉。解决方法是用树状数组维护后缀单调栈,同样要支持撤销。
听着很简单,但代码不是很好写。
代码
第82行少打一个\(dep\)调了一下午,身败名裂……
#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 202200
typedef long long ll;
typedef double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
inline void print(register ll x)
{
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
}
void file()
{
#ifdef NTFOrz
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
int n;
#define N (n+10)
struct hh{int t;ll w;int nxt;}edge[sz<<1];
int head[sz],ecnt;
void make_edge(int f,int t,ll w){edge[++ecnt]=(hh){t,w,head[f]};head[f]=ecnt;}
ll dep[sz],dp[sz],P[sz],Q[sz],L[sz];
int a[sz],c;
#define Convex vector<int>
Convex tr[sz];int siz[sz];
ll Calc(int id,ll k)
{
if (!siz[id]) return 1e18;
int l=0,r=siz[id]-1;
while (233)
{
if (r-l<=10)
{
ll ret=1e18;
rep(i,l,r) chkmin(ret,dp[tr[id][i]]-k*dep[tr[id][i]]);
return ret;
}
int mid=(l+r)>>1;
if (dp[tr[id][mid]]-k*dep[tr[id][mid]]<dp[tr[id][mid+1]]-k*dep[tr[id][mid+1]]) r=mid;
else l=mid+1;
}
}
ll calc(int x,ll k){ll ret=1e18;while (x) chkmin(ret,Calc(x,k)),x-=(x&(-x));return ret;}
struct hhh{int x,y,siz;};
map<pii,hhh>M;
db K(int x,int y){return 1.0*(dp[y]-dp[x])/(dep[y]-dep[x]);}
void Insert(int id,int x)
{
int l=1,r=siz[id]-1,pos=(int)tr[id].size();
while (l<=r)
{
int p=(l+r)>>1;
if (dep[tr[id][p-1]]==dep[x])
{
if (dp[tr[id][p-1]]<=dp[x]) return;
else pos=p-1,r=p-2;
continue;
}
if (K(tr[id][p-1],x)<K(tr[id][p-1],tr[id][p])) pos=p,r=p-1;
else l=p+1;
}
if (siz[id]&&dep[tr[id][siz[id]-1]]==dep[x]&&dp[tr[id][siz[id]-1]]<=dp[x]) return;
if (pos==(int)tr[id].size())
{
if (pos==siz[id])
{
tr[id].push_back(x);
M[MP(x,id)]=(hhh){pos,-1,siz[id]};++siz[id];
return;
}
pos=siz[id];
}
M[MP(x,id)]=(hhh){pos,tr[id][pos],siz[id]};tr[id][pos]=x;siz[id]=pos+1;
}
void insert(int x,int p){while (p<=N) Insert(p,x),p+=(p&(-p));}
void Reset(int id,int x)
{
hhh s=M[MP(x,id)];
tr[id][s.x]=s.y;siz[id]=s.siz;
if (s.y==-1) tr[id].pop_back();
}
void reset(int x,int p){while (p<=N) Reset(p,x),p+=(p&(-p));}
void dfs(int x,int fa)
{
a[++c]=x;insert(x,N-c);
#define v edge[i].t
go(x) if (v!=fa)
{
dep[v]=dep[x]+edge[i].w;
int l=1,r=c,pos;
while (l<=r)
{
int mid=(l+r)>>1;
if (dep[v]-dep[a[mid]]<=L[v]) pos=mid,r=mid-1;
else l=mid+1;
}
dp[v]=calc(N-pos,P[v])+P[v]*dep[v]+Q[v];
dfs(v,x);
}
reset(x,N-c);--c;
}
int main()
{
file();
int _;
read(n,_);
int x;ll y;
rep(i,2,n) read(x,y,P[i],Q[i],L[i]),make_edge(x,i,y);
dfs(1,0);
rep(i,2,n) print(dp[i]);Ot();
return 0;
}
洛谷P2305 [NOI2014]购票 [DP,树状数组]的更多相关文章
- [洛谷P1198/BZOJ1012][JSOI2008] 最大数 - 树状数组/线段树?
其实已经学了树状数组和线段树,然而懒得做题,所以至今没写多少博客 Description 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数 ...
- 洛谷P3688/uoj#291. [ZJOI2017]树状数组
传送门(uoj) 传送门(洛谷) 这里是题解以及我的卡常数历程 话说后面那几组数据莫不是lxl出的这么毒 首先不难发现这个东西把查询前缀和变成了查询后缀和,结果就是查了\([l-1,r-1]\)的区间 ...
- 洛谷P3368 【模板】树状数组 2
P3368 [模板]树状数组 2 102通过 206提交 题目提供者HansBug 标签 难度普及/提高- 提交 讨论 题解 最新讨论 暂时没有讨论 题目描述 如题,已知一个数列,你需要进行下面两 ...
- 洛谷P3374 【模板】树状数组 1
P3374 [模板]树状数组 1 140通过 232提交 题目提供者HansBug 标签 难度普及/提高- 提交 讨论 题解 最新讨论 题目描述有误 题目描述 如题,已知一个数列,你需要进行下面两 ...
- 洛谷 P3368 【模板】树状数组 2
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...
- 洛谷 P3374 【模板】树状数组 1
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...
- 树状数组模板(pascal) 洛谷P3374 【模板】树状数组1
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...
- 洛谷 P3368 【模板】树状数组 2(区间修改点查询)
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的值 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...
- 洛谷 P3368 【模板】树状数组 2 题解
P3368 [模板]树状数组 2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的值 输入格式 第一行包含两个整数N.M,分别表示该数列数字的个 ...
随机推荐
- Android GridView去除自带边框点击效果、去除右侧滚动条、禁止上下滑动
一.去除自带边框点击效果: <com.example.gridview.MyGridView android:id="@+id/grid_upload_pictures" a ...
- javascript 之 命名空间
注意点: 1/IIFE是现代js框架最主要的基础设施,保证变量不被污染. 2/基本上我们把命名空间等同于框架的名字. 内容 一.简单的命名空间 <input type="button& ...
- 编写Postgres扩展之三:调试
原文:http://big-elephants.com/2015-10/writing-postgres-extensions-part-iii/ 编译:Tacey Wong 在上一篇关于编写Post ...
- iOS - 如何适配iOS10(插曲)
升级了系统10.12beta xcode8 出现一大推问题 ,连上架APP都成了问题.只能先解决这些问题,再研究3D引擎了. 2016年9月7日,苹果发布iOS 10.2016年9月14日,全新的操 ...
- h5 点击ios键盘完成 出现键盘大小的白块
document.addEventListener('focusout', function (e) { window.scrollTo() }) 源文件链接 https://blog.csdn.ne ...
- TLS1.3 PPT 整理
1.握手协议的目的是什么 建立共享秘钥(通常使用公钥加密).协商算法和模型以及加密使用的参数,验证身份. 2.记录协议 传输独立的信息,在堆成加密算法下保护数据传输 3.RSA Handshake S ...
- 剖析gcc -v输出
分析gcc -v的详细信息的意义 首先我们需要清楚一点,我们并不能完全弄清楚gcc -v的所有信息,因为毕竟我们并不是GCC编译器集合的实现者,对于这些信息,他们才是最清楚的.由于我们不能将所有的信息 ...
- 解析Linux中LVM与磁盘配额
LVM 逻辑卷管理 LVM 概述 LVM 是 Linux 操作系统中对磁盘分区进行管理的一种逻辑机制,它是建立在硬盘和分区之上.文件系统之下的一个逻辑层,在建立文件系统时屏蔽了下层的磁盘分区布局,因此 ...
- jmeter+jenkins 配置过程(很详细)
一.安装jmeter 第一步 安装JDK,配置JDK路径.注:jdk下载地址,推荐使用jdk1.8版本 http://www.oracle.com/technetwork/java/javase/d ...
- springboot ElasticSearch 简单的全文检索高亮
原文:https://segmentfault.com/a/1190000017324038?utm_source=tag-newest 首先引入依赖 <dependency> <g ...