bzoj3672/luogu2305 购票 (运用点分治思想的树上cdq分治+斜率优化dp)
我们都做过一道题(?)货币兑换,是用cdq分治来解决不单调的斜率优化
现在它放到了树上..
总之先写下来dp方程,$f[i]=min\{f[j]+(dis[i]-dis[j])*p[i]+q[i]\} ,j是i的祖先,dis[i]-dis[j]<=l[i]$ ,其中dis[i]表示1号点到i号点的距离
可以很明显的看出斜率优化,但我们要放到树上做
于是就运用点分治的思想来找重心(正如普通的cdq是找中点一样)
步骤是这样的:
1.对于根为x的一个子树,我们先找到它的重心rt
2.把rt的子树刨掉,但留下rt,然后递归地再做x,目的是先算出祖先们的答案,为更新孩子们做准备
3.把rt在子树x中的祖先按深度排序,把rt的子树(不包括rt)按照它们最远能到的祖先的深度排序,然后一边插祖先维护一个凸包,一边给孩子统计答案
4.递归地做rt的子节点
斜率优化的细节就不写了(因为全是蒙出来的)
#include<bits/stdc++.h>
#define pa pair<int,int>
#define ll long long
using namespace std;
const int maxn=2e5+,inf=0x3f3f3f3f; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} struct Edge{
int b,ne;ll l;
}eg[maxn*];
int fa[maxn][],egh[maxn],ect;
int N,NN,dep[maxn],ldep[maxn];
int siz[maxn],root;
int cnt[maxn],tmpl[maxn],tmpr[maxn],pct;
int stk[maxn];
ll dp[maxn],dis[maxn],p[maxn],q[maxn],l[maxn];
bool vis[maxn]; void dfs1(int x){
int i;
for(i=;fa[x][i-]&&fa[fa[x][i-]][i-];i++) fa[x][i]=fa[fa[x][i-]][i-];
int y=x;for(ll j=l[x];i>=;i--){
if(fa[y][i]&&dis[y]-dis[fa[y][i]]<=j)
j-=dis[y]-dis[fa[y][i]],y=fa[y][i];
}
if(y!=x) ldep[x]=dep[y];
else ldep[x]=-; for(i=egh[x];i;i=eg[i].ne){
int b=eg[i].b;
dis[b]=dis[x]+eg[i].l;
dep[b]=dep[x]+;
dfs1(b);
}
} void getroot(int x,int smsiz,int &ms,int &root){
siz[x]=;int mm=;
for(int i=egh[x];i;i=eg[i].ne){
int b=eg[i].b;if(vis[b]) continue;
getroot(b,smsiz,ms,root);siz[x]+=siz[b];
mm=max(mm,siz[b]);
}mm=max(mm,smsiz-siz[x]);
if(mm<=ms) ms=mm,root=x;
}
void getson(int x){
tmpr[++pct]=x;
for(int i=egh[x];i;i=eg[i].ne){
int b=eg[i].b;if(vis[b]) continue;
getson(b);
}
} inline bool cmp(int a,int b){
return ldep[a]>ldep[b];
} inline double getk(int a,int b){
return (double)(dp[a]-dp[b])/(dis[a]-dis[b]);
} void cdq(int x,int s){
if(s<=) return;
int rt,ms=inf;
getroot(x,s,ms,rt);
if(x!=rt){
int sms=s,mmm=inf;
for(int i=egh[rt];i;i=eg[i].ne) vis[eg[i].b]=,sms-=siz[eg[i].b];
cdq(x,sms);
}int l=;
for(int i=rt;i!=fa[x][];i=fa[i][]) tmpl[++l]=i;
pct=;
for(int i=egh[rt];i;i=eg[i].ne) getson(eg[i].b);
sort(tmpr+,tmpr+pct+,cmp); int sh=;
for(int i=,j=;i<=pct&&ldep[tmpr[i]]!=-;i++){
for(;j<=l&&dep[tmpl[j]]>=ldep[tmpr[i]];j++){
while(sh>&&getk(stk[sh],stk[sh-])<=getk(stk[sh],tmpl[j])) --sh;
stk[++sh]=tmpl[j];
}
if(sh){
int k=stk[];
if(sh!=){
int a=,b=sh-;
while(a<=b){
int m=(a+b)>>;
if(getk(stk[m],stk[m+])<=p[tmpr[i]]) k=stk[m],b=m-;
else k=stk[m+],a=m+;
}
}
dp[tmpr[i]]=min(dp[tmpr[i]],dp[k]+(dis[tmpr[i]]-dis[k])*p[tmpr[i]]+q[tmpr[i]]);
}
}
for(int i=egh[rt];i;i=eg[i].ne){
cdq(eg[i].b,siz[eg[i].b]);
}
} inline void adeg(int a,int b,int l){
eg[++ect].b=b;eg[ect].l=l;eg[ect].ne=egh[a];egh[a]=ect;
} int main(){
int i,j,k;
N=rd();rd();
for(i=;i<=N;i++){
int a=rd(),b=rd();p[i]=rd(),q[i]=rd(),l[i]=rd();
adeg(a,i,b);fa[i][]=a;
}ldep[]=-;dep[]=;dfs1();
memset(dp,,sizeof(dp));dp[]=;
cdq(,N);
for(i=;i<=N;i++) printf("%lld\n",dp[i]);
return ;
}
bzoj3672/luogu2305 购票 (运用点分治思想的树上cdq分治+斜率优化dp)的更多相关文章
- 【BZOJ-3672】购票 树分治 + 斜率优化DP
3672: [Noi2014]购票 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 1177 Solved: 562[Submit][Status][ ...
- 【bzoj3672】[Noi2014]购票 斜率优化dp+CDQ分治+树的点分治
题目描述 给出一棵以1为根的带边权有根树,对于每个根节点以外的点$v$,如果它与其某个祖先$a$的距离$d$不超过$l_v$,则可以花费$p_vd+q_v$的代价从$v$到$a$.问从每个点到1花费 ...
- [Noi2014]购票 斜率优化DP+可持久化凸包
貌似网上大部分题解都是CDQ分治+点分治然后再斜率优化DP,我貌似并没有用这个方法. 这一题跟这题有点像,只不过多了一个l的限制 如果说直接跑斜率优化DP,存储整个序列的话,显然是不行的,如图所示(图 ...
- 【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 ...
- BZOJ1492:[NOI2007]货币兑换 (CDQ分治+斜率优化DP | splay动态维护凸包)
BZOJ1492:[NOI2007]货币兑换 题目传送门 [问题描述] 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和B纪念券(以下简称B券).每个持有金券的 ...
- BZOJ3672: [Noi2014]购票【CDQ分治】【点分治】【斜率优化DP】
Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的 ...
- UOJ#7 NOI2014 购票 点分治+凸包二分 斜率优化DP
[NOI2014]购票 链接:http://uoj.ac/problem/7 因为太麻烦了,而且暴露了我很多学习不扎实的问题,所以记录一下具体做法. 主要算法:点分治+凸包优化斜率DP. 因为$q_i ...
- BZOJ 3672: [Noi2014]购票 树上CDQ分治
做这道题真的是涨姿势了,一般的CDQ分治都是在序列上进行的,这次是把CDQ分治放树上跑了~ 考虑一半的 CDQ 分治怎么进行: 递归处理左区间,处理左区间对右区间的影响,然后再递归处理右区间. 所以, ...
- BZOJ 3963: [WF2011]MachineWorks [CDQ分治 斜率优化DP]
传送门 当然了WF的题uva hdu上也有 你的公司获得了一个厂房N天的使用权和一笔启动资金,你打算在这N天里租借机器进行生产来获得收益.可以租借的机器有M台.每台机器有四个参数D,P,R,G.你可以 ...
随机推荐
- ElasticSearch实践系列(一):安装
Elasticsearch简介 Elasticsearch是一个高度可扩展的开源全文搜索和分析引擎.它允许您快速,近实时地存储,搜索和分析大量数据.它通常用作底层引擎/技术,为具有复杂搜索功能和要求的 ...
- HTTP Error 500.22 - Internal Server Error 错误解决方案
1. 首先进入IIS ,配置IIS 应用程序池的.Net Framework版本 2. 点击左侧应用程序池,再单机右侧设置,选择版本 3. 设置为经典模式 如若遇到以下错误: 解决方案:删除confi ...
- zookeeper Error contacting service 解决
连接kafka集群,有一个kafka机器连接失败 到该kafka机器上查询kafka进程,发现没有, 再查看zookeeper状态,提示 Error contacting service. It is ...
- 分布式监控系统Zabbix3.4-钉钉告警配置记录
群机器人是钉钉群的高级扩展功能,群机器人可以将第三方服务的信息聚合到群聊中,实现自动化的信息同步.例如:通过聚合GitHub,GitLab等源码管理服务,实现源码更新同步:通过聚合Trello,JIR ...
- LInux系统木马植入排查分析 及 应用漏洞修复配置(隐藏bannner版本等)
在日常繁琐的运维工作中,对linux服务器进行安全检查是一个非常重要的环节.今天,分享一下如何检查linux系统是否遭受了入侵? 一.是否入侵检查 1)检查系统日志 检查系统错误登陆日志,统计IP重试 ...
- python-小知识点-14
''' python2 python3 ''' #python2 print() print 'abc' range() xrange() 生成器 raw_input() #python3 print ...
- 龟速机器学习总结----day1
机器学习主要工作大致分为以下几步,数据预处理,包括数据切分,特征选取,数据缺失值处理,来了解数据.接下来分割数据,分别分出训练集和测试集.第三步,选择模型,使用训练数据训练模型参数,再对测试数据进行预 ...
- 【个人阅读】软件工程M1/M2阶段总结
这次作业是好久以前布置的,由于学期末课程设计任务比较重,我在完善M2阶段的代码的同时又忙于数据库的实现和编译器的实现,一度感觉忙得透不过气来....到这些都基本完成的时候,会看自己以前的阅读心得,觉得 ...
- PAT 1071 小赌怡情
https://pintia.cn/problem-sets/994805260223102976/problems/994805264312549376 常言道“小赌怡情”.这是一个很简单的小游戏: ...
- CS、IP和PC寄存器
CS寄存器和IP寄存器: 首先强调一下,这两个寄存器非常非常重要,CS的全拼为“Code segment”,即代码段寄存器,对应于内存中的存放代码的内存区域,用来存放内存代码段区域的入口地址(段基址) ...