洛谷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,分别表示该数列数字的个 ...
随机推荐
- 滤波器算法(2)-最小均方(LMS)
2018.09.09 写的版本 ①残差平方和 ②平方损失函数: ③函数的极值点为偏导数为0的点:(将问题变成一个求极值的问题) ④求解得: matlab代码: ① y=ax+b+e方程 functio ...
- 使用docker搭建reids主从,哨兵。
Redis主从配置,如果没有真机就要用虚拟机,使用Docke for Windows host网络有问题. 准备: 1.安装虚拟机. 2.下载redis的安装文件:http://download.re ...
- C#不支持XPATH2.0
.net中的XPATH是1.0版本的,很多2.0中的函数是不兼容的,比如lower-case().replace()函数等,下面中的XPATH语句在运行时会报错 //table[contains(lo ...
- Springboot2.x整合Redis以及连接哨兵模式/集群模式
依赖: <!--spirngboot版本为2.x--><!-- 加载spring boot redis包,springboot2.0中直接使用jedis或者lettuce配置连接池, ...
- js实现图片的Blob base64 ArrayBuffer 的各种转换
一.相关基础知识 构造函数 FileReader() 返回一个新构造的FileReader 事件处理 FileReader.onabort 处理abort事件.该事件在读取操作被中断时触发. Fil ...
- node.js 调用mysql 数据库
1.在package.json中添加mysql依赖 命令:npm install mysql --save 2.项目中添加mysql文件夹 > 文件夹下创建config文件夹,并在config下 ...
- CEIWEI CommTone串口调试精灵7.1 串口调试 串口工具
CEIWEI CommTone串口调试精灵 是一款功能强大的串行端口通信调试软件,内嵌超过100种标准的CRC校验功能,并支校验结果高低位字节前导转换:支持批量协议调试,并支持文件.16进制.UN ...
- 模板引擎-vue中的模板如何被解析,指令如何处理
模板是什么 <div id='app'> <div> <input v-model="title"/> <button v-on:clic ...
- kali系统无法使用ll命令
ll命令:也就是ls -l的缩写方式. 重装kali系统之后,发现无法使用ll命令了,于是写一个笔记记录一下如何添加ll命令. 解决方法: vim ~/.bashrc 将alias ll=’ls -l ...
- django实现发送邮件功能
django实现邮件发送功能 1)首先注册一个邮箱,这里以163邮箱为例 2)注册之后登录,进行如下修改 找到设置,设置一个授权码,授权码的目的仅仅是让你有权限发邮件,但是不能登录到邮箱进行修改,发送 ...