●BZOJ 3672 [Noi2014]购票
题链:
http://www.lydsy.com/JudgeOnline/problem.php?id=3672
题解:
斜率优化DP,点分治(树上CDQ分治...)
这里有一个没有距离限制的简单版:BZOJ 1767 [Ceoi2009]harbingers
定义$DP[i]$为从i出发到1号点的最小花费,$dis_i$为i到1号点的距离:
转移:
$DP[i]=min(DP[j]+(dis_i-dis_j)P_j)+Q_i$
$\quad=min(DP[j]-dis_jP_i)+dis_iP_i+Q_i$
显然这个$O(N^2)$的转移会超时。
考虑优化:
假设对于当前计算的DP[i],有两个转移来源点:k,j,同时dis[k]<dis[j],设j点比k点优。
那么有:$DP[j]-dis_j*P_i-(DP[k]-dis_k*P_i)<0$
则: $\frac{DP[j]-DP[k]}{dis[j]-dis[k]}<P[i]$
如果令 Slope(j,k)=$\frac{DP[j]-DP[k]}{dis[j]-dis[k]}$
那么得到结论,如果 $dis_k<dis_j$,且Slope(j,k)<P[i]的话,则j点优于k点。
同时如果存在三个转移来源点:k,j,i,满足$dis_k<dis_j<dis_i$,
同时Slope(i,j)<Slope(j,k),则j点无效。
所以对于每个来源点二元组(dis[j],DP[j]),只需要在平面上维护一个下凸壳即可。
1).如果问题不在一颗树上,而是在一个序列上,这个应该比较容易吧:一个裸的CDQ就可以解决了。
2).而如果问题没有limit这个距离限制,即使在树上,也比较容易了,因为随着DFS遍历树时,dis是单增的,所以可以直接维护单调栈(详细见BZOJ 1767 [Ceoi2009]harbingers)
但是现在既在树上又有距离限制怎么办呢?这里采用点分治来实现CDQ分治的功能,(可以叫做树上CDQ分治么)
对于当前的子树,我们令根为u,(这个根是子树内的点在前往1号点时都要经过的地方)。
并找到子树内的重心cg(the center of gravity),
然后先递归处理cg为根时含有u的那颗子树,
不难发现,cg的其它子树的点(令这些点的集合为R)在前往1号点时,都会进过cg~u这一条链,
即这条链上的点可能会成为R里的点的转移点。
同时为了满足距离这一限制,即每个点i最多只能向上到达 $dis_i-limit_i$这个位置
所以把R里的点按 $dis_i-limit_i$排序后,从大到小枚举R里的i点,并把cg~u这条链上dis小于$dis_i-limit_i$的点用单调栈维护一个下凸壳。
接着在凸壳里二分最优的转移来源点即可。
整个过程是$O(Nlog_2^2N)$的。
(伤不起,读入居然要long long!)
代码:PoPoQQQ的代码写得很棒呀!
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 200050
#define ll long long
using namespace std;
ll DP[MAXN],P[MAXN],Q[MAXN],G[MAXN],dis[MAXN];
int fa[MAXN],siz[MAXN];
int N,t;
struct Edge{
ll val[MAXN];
int to[MAXN],nxt[MAXN],head[MAXN],ban[MAXN],ent;
Edge(){ent=2;}
void Adde(int u,int v,ll w){
to[ent]=v; val[ent]=w; nxt[ent]=head[u]; head[u]=ent++;
}
}E;
struct Mostk{
int s[MAXN],top;
#define Slope(i,j) (1.0*(DP[i]-DP[j])/(dis[i]-dis[j]))
void Reset(){top=0;}
void Push(int i){
if(top&&dis[s[top]]==dis[i])
{if(DP[i]<DP[s[top]]) top--; else return;}
while(top>1&&Slope(s[top-1],s[top])<Slope(s[top],i)) top--;
s[++top]=i;
}
int Query(int i){//二分单调栈
static int l,r,mid,ret;
if(!top) return 0;
l=2; r=top; ret=1;
while(l<=r){
mid=(l+r)>>1;
if(Slope(s[mid-1],s[mid])>=P[i]) ret=mid,l=mid+1;
else r=mid-1;
}
return s[ret];
}
}S;
void dfs(int u){
for(int i=E.head[u];i;i=E.nxt[i]){
int v=E.to[i];
dis[v]=dis[u]+E.val[i];
dfs(v);
}
}
void getcg(int u,int &cg,int &num,int sum){
int maxnum=0; siz[u]=1;
for(int i=E.head[u];i;i=E.nxt[i]){
int v=E.to[i]; if(E.ban[i]) continue;
getcg(v,cg,num,sum);
maxnum=max(maxnum,siz[v]);
siz[u]+=siz[v];
}
maxnum=max(maxnum,sum-siz[u]);
if(maxnum<=num) num=maxnum,cg=u;
}
void trave(int u,int &cr,int *R){
R[++cr]=u;
for(int i=E.head[u];i;i=E.nxt[i]){
if(E.ban[i]) continue;
trave(E.to[i],cr,R);
}
}
bool cmp(int i,int j){
return dis[i]-G[i]>dis[j]-G[j];
}
void solve(int u,int num){
static int R[MAXN],cr,maxnum;
if(num==1) return;
int cg=u; maxnum=num;
getcg(u,cg,maxnum,num);
//-----------------------------准备递归u区域
for(int i=E.head[cg];i;i=E.nxt[i]) E.ban[i]=1;
solve(u,num-siz[cg]+1);
//-----------------------------开始解决当前层的贡献
cr=0; S.Reset();
for(int i=E.head[cg];i;i=E.nxt[i]) trave(E.to[i],cr,R);
sort(R+1,R+cr+1,cmp);
for(int i=1,j=cg,k;i<=cr;i++){
while(j!=fa[u]&&dis[j]>=dis[R[i]]-G[R[i]]) S.Push(j),j=fa[j];
k=S.Query(R[i]);
if(k) DP[R[i]]=min(DP[R[i]],DP[k]+(dis[R[i]]-dis[k])*P[R[i]]+Q[R[i]]);
}
//-----------------------------递归解决剩下子树区域
for(int i=E.head[cg];i;i=E.nxt[i])
solve(E.to[i],siz[E.to[i]]);
}
void read(ll &x){
static int sn; static char ch;
x=0; sn=1; ch=getchar();
while(ch<'0'||'9'<ch){if(ch=='-')sn=-1;ch=getchar();}
while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
x=x*sn;
}
int main(){
scanf("%d%d",&N,&t);
memset(DP,0x3f,sizeof(DP));
DP[1]=0; ll f,s,p,q,g;
for(int i=2;i<=N;i++){
read(f); read(s); read(p); read(q); read(g);
fa[i]=f; P[i]=p; Q[i]=q; G[i]=g;
E.Adde(f,i,s);
}
dfs(1);
solve(1,N);
for(int i=2;i<=N;i++) printf("%lld\n",DP[i]);
return 0;
}
●BZOJ 3672 [Noi2014]购票的更多相关文章
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- bzoj 3672: [Noi2014]购票 树链剖分+维护凸包
3672: [Noi2014]购票 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 480 Solved: 212[Submit][Status][D ...
- BZOJ 3672: [Noi2014]购票( 树链剖分 + 线段树 + 凸包 )
s弄成前缀和(到根), dp(i) = min(dp(j) + (s(i)-s(j))*p(i)+q(i)). 链的情况大家都会做...就是用栈维护个下凸包, 插入时暴力弹栈, 查询时就在凸包上二分/ ...
- BZOJ 3672 [Noi2014]购票 (熟练剖分+凸壳维护)
题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3672 题意:给出一棵有根树(1为根),边有长度.每个点u有三个属性(len[u], ...
- bzoj 3672: [Noi2014]购票
Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的 ...
- BZOJ 3672 [NOI2014]购票 (凸优化+树剖/树分治)
题目大意: 略 题面传送门 怎么看也是一道$duliu$题= = 先推式子,设$dp[x]$表示到达$x$点到达1节点的最小花费 设$y$是$x$的一个祖先,则$dp[x]=min(dp[y]+(di ...
- BZOJ 3672: [Noi2014]购票 树上CDQ分治
做这道题真的是涨姿势了,一般的CDQ分治都是在序列上进行的,这次是把CDQ分治放树上跑了~ 考虑一半的 CDQ 分治怎么进行: 递归处理左区间,处理左区间对右区间的影响,然后再递归处理右区间. 所以, ...
- 【BZOJ 3672】 3672: [Noi2014]购票 (CDQ分治+点分治+斜率优化)**
3672: [Noi2014]购票 Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国 ...
- bzoj千题计划251:bzoj3672: [Noi2014]购票
http://www.lydsy.com/JudgeOnline/problem.php?id=3672 法一:线段树维护可持久化单调队列维护凸包 斜率优化DP 设dp[i] 表示i号点到根节点的最少 ...
随机推荐
- tornado options
tornado.options.define() 用来定义options选项变量的方法,定义的变量可以在全局的tornado.options.options中获取使用,传入参数: name 选项变量名 ...
- router问题
var http = require("http"); var router = require("./router.js"); //创建服务器 var ser ...
- vivado License导入方法与资源获取
前言 以下安装说明基于已经正确安装vivado 笔者操作环境:linux vivado版本:2015.2 vivado License导入方法: 点击菜单栏[Help],选择[Manage Licen ...
- Scrum 冲刺 第七日
Scrum 冲刺 第七日 站立式会议 燃尽图 今日任务安排 项目发布说明 站立式会议 返回目录 燃尽图 返回目录 今日任务安排 返回目录 项目发布说明 本版本的新功能 不只是简单打地鼠,还有一些不能打 ...
- 基于Unity·UGUI实现的RecycleList循环列表UI容器
在UI功能开发实践中,列表UI容器是我们经常使用一种UI容器组件.这种组件就根据输入的数据集合生成对应数据项目.从显示的方向来说,一般就分为水平排布和垂直排布的列表容器两种.列表容器为了在有限的界面空 ...
- Raid 5数据恢复原理以及raid 5数据恢复实际操作案例
Raid 5数据恢复算法原理 要理解 raid 5数据恢复原理首先要先认识raid5,"分布式奇偶校验的独立磁盘结构"也就是我们称之为的raid 5数据恢复有一个概念需要理解,也就 ...
- SpringMVC源码情操陶冶#task-executor解析器
承接Spring源码情操陶冶-自定义节点的解析.线程池是jdk的一个很重要的概念,在很多的场景都会应用到,多用于处理多任务的并发处理,此处借由spring整合jdk的cocurrent包的方式来进行深 ...
- nyoj 移位密码
移位密码 时间限制:1000 ms | 内存限制:65535 KB 难度:0 描述 移位密码是最简单的一类代替密码,具体算法就是将字母表的字母右移k个位置(k<26),并对字母表长度作模 ...
- JAVA_SE基础——27.匿名对象
黑马程序员入学blog... 匿名对象:没有引用类型变量指向的对象称作为匿名对象. 匿名对象要注意的事项:1. 我们一般不会给匿名对象赋予属性值,因为永远无法获取到.2. 两个匿名对象永远都不可能是同 ...
- vue组件详解(五)——组件高级用法
一.递归组件 组件在它的模板内可以递归地调用自己, 只要给组件设置name 的选项就可以了. 示例如下: <div id="app19"> <my-compone ...