[BZOJ 2809] Dispatching
Link:https://www.lydsy.com/JudgeOnline/problem.php?id=2809
Algorithm:
很容易看出此题贪心的思路:
只要在每个点的子树中贪心选取费用最小的,使其总和不超过m即可
维护最小值,想到用堆,但普通的堆无法进行合并
于是用到数据结构可并堆/左偏树来在O(logN)的时间内合并堆
可并堆和左偏树的区别仅仅在于左偏树多维护了dist数组,而可并堆是无脑交换左右子树
这也使得左偏树的复杂度是能证明的O(logN),而可并堆仅仅是均摊复杂度为O(logN),因此还是尽量用左偏树吧
证明:n个节点的左偏树的距离dist最大为log(n+1)-1
若左偏树的距离为一定值,则节点数最少的左偏树是完全二叉树。
设一棵左偏树的距离为k,则这棵左偏树至少有2^{k+1}-1个节点。
因为n>=2^{k+1}-1,所以k<=log(n+1)-1
Code:
左偏树:
#include <bits/stdc++.h> using namespace std;
typedef long long ll; inline int read()
{
char ch;int num,f=;
while(!isdigit(ch=getchar())) f|=(ch=='-');
num=ch-'';
while(isdigit(ch=getchar())) num=num*+ch-'';
return f?-num:num;
} const int MAXN=1e5+;
vector<int> G[MAXN];
struct LTree
{
int ls,rs,dist,val;
ll siz,sum;
}Lt[MAXN]; int n,m,C[MAXN],L[MAXN],root[MAXN];
ll res=; int merge(int x,int y)
{
if(!x || !y) return x+y;
if(Lt[x].val<Lt[y].val) swap(x,y);
Lt[x].rs=merge(Lt[x].rs,y); if(Lt[Lt[x].ls].dist<Lt[Lt[x].rs].dist) swap(Lt[x].ls,Lt[x].rs);
Lt[x].dist=Lt[Lt[x].rs].dist+;
Lt[x].siz=Lt[Lt[x].rs].siz+Lt[Lt[x].ls].siz+;
Lt[x].sum=Lt[Lt[x].rs].sum+Lt[Lt[x].ls].sum+Lt[x].val; return x;
} void pop(int &x)
{
x=merge(Lt[x].ls,Lt[x].rs);
} void dfs(int x)
{
root[x]=x;
for(int i=;i<G[x].size();i++)
dfs(G[x][i]),root[x]=merge(root[x],root[G[x][i]]);
while(Lt[root[x]].siz && Lt[root[x]].sum>m) pop(root[x]);
res=max(res,L[x]*Lt[root[x]].siz);
} int main()
{
n=read();m=read();
for(int i=;i<=n;i++)
{
int x=read();G[x].push_back(i);
C[i]=read();L[i]=read();
Lt[i].sum=Lt[i].val=C[i];Lt[i].siz=;
} dfs();
cout << res;
return ;
}
可并堆:
#include <bits/stdc++.h> using namespace std;
typedef long long ll; inline int read()
{
char ch;int num,f=;
while(!isdigit(ch=getchar())) f|=(ch=='-');
num=ch-'';
while(isdigit(ch=getchar())) num=num*+ch-'';
return f?-num:num;
} const int MAXN=1e5+;
vector<int> G[MAXN]; int n,m,C[MAXN],L[MAXN],root[MAXN];
ll res=; struct SkewHeap
{
int v[MAXN],ls[MAXN],rs[MAXN];
ll siz[MAXN],sum[MAXN]; int merge(int x,int y)
{
if(!x || !y) return x+y;
if(v[x]<v[y]) swap(x,y);
rs[x]=merge(rs[x],y);
swap(ls[x],rs[x]); sum[x]=sum[ls[x]]+sum[rs[x]]+v[x];
siz[x]=siz[ls[x]]+siz[rs[x]]+;
return x;
} void pop(int &x){x=merge(ls[x],rs[x]);}
}Heap; void dfs(int x)
{
root[x]=x;
for(int i=;i<G[x].size();i++)
dfs(G[x][i]),root[x]=Heap.merge(root[x],root[G[x][i]]);
while(Heap.siz[root[x]] && Heap.sum[root[x]]>m) Heap.pop(root[x]);
res=max(res,L[x]*Heap.siz[root[x]]);
} int main()
{
n=read();m=read();
for(int i=;i<=n;i++)
{
int x=read();G[x].push_back(i);
C[i]=read();L[i]=read();
Heap.siz[i]=;Heap.sum[i]=Heap.v[i]=C[i];
} dfs();
cout << res;
return ;
}
Review:
1、对于每棵左偏树,最好用root[x]记录其根节点
2、对于左偏树要跟着维护的信息,
在merge的最后进行更新
3、可选择将整个数据结构封装在一个类中,写起来可能方便点
[BZOJ 2809] Dispatching的更多相关文章
- BZOJ - 2809 dispatching 主席树+dfs序
在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都有且仅有一个上级.为保密,同时增强忍者们的 ...
- 【BZOJ 2809 dispatching】
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 4393 Solved: 2246[Submit][Status][Discuss] Descript ...
- BZOJ 2809: [Apio2012]dispatching( 平衡树 + 启发式合并 )
枚举树上的每个结点做管理者, 贪心地取其子树中薪水较低的, 算出这个结点为管理者的满意度, 更新答案. 用平衡树+启发式合并, 时间复杂度为O(N log²N) ------------------- ...
- bzoj 2809: [Apio2012]dispatching -- 可并堆
2809: [Apio2012]dispatching Time Limit: 10 Sec Memory Limit: 128 MB Description 在一个忍者的帮派里,一些忍者们被选中派 ...
- 【BZOJ 2809】2809: [Apio2012]dispatching (左偏树)
2809: [Apio2012]dispatching Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Maste ...
- AC日记——dispatching bzoj 2809
2809: [Apio2012]dispatching Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3290 Solved: 1740[Submi ...
- BZOJ 2809 APIO2012 dispatching Treap+启示式合并 / 可并堆
题目大意:给定一棵树,选定一棵子树中的一些点,薪水和不能超过m,求点的数量*子树根节点的领导能力的最大值 考虑对于每一个节点,我们维护一种数据结构,在当中贪心寻找薪金小的雇佣. 每一个节点暴力重建一定 ...
- BZOJ 2809: [Apio2012]dispatching(左偏树)
http://www.lydsy.com/JudgeOnline/problem.php?id=2809 题意: 思路:最简单的想法就是枚举管理者,在其子树中从薪水低的开始选起,但是每个节点都这样处理 ...
- BZOJ 2809 [Apio2012]dispatching(斜堆+树形DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2809 [题目大意] 给出一棵树,求出每个点有个权值,和一个乘算值,请选取一棵子树, 并 ...
随机推荐
- [USACO Hol10] 臭气弹 图上期望概率dp 高斯
记住一开始和后来的经过是两个事件因此概率可以大于一 #include<cstdio> #include<iostream> #include<cstdlib> #i ...
- jrebel插件激活
不管用的哪个工具都可以通过下面的教程获取注册码,激活你的开发工具 原文出自:http://www.gezila.com/tutorials/11476.html 首先打开Myeclipse,点击“he ...
- HDU2057
http://acm.hdu.edu.cn/showproblem.php?pid=2057 涉及到16进制内的加法,可以用%I64x直接来处理,要注意到16进制中负数是用补码来表示的.一个比较困惑的 ...
- pageContext对象的用法详述
pageContext对象 这个对象代表页面上下文,该对象主要用于访问JSP之间的共享数据. pageContext是PageContext类的实例,使用pageContext可以访问page.re ...
- 【洛谷 P1337】[JSOI2004]平衡点 / 吊打XXX (模拟退火)
题目链接 正解就算了吧,谁叫我理生化 语数外 政史地都菜呢 模拟退火真玄学,不知道发生了什么就跑出答案了,原理就算了吧,能用(pianfen)就好. 当重物平衡时,势能一定是最小的,于是当我随机出一个 ...
- CSS3 3D 转换
CSS3 允许您使用 3D 转换来对元素进行格式化. 在本章中,您将学到其中的一些 3D 转换方法: rotateX() rotateY() rotateX() 方法 rotateX()方法,围绕其在 ...
- MySQL 之 foreign key
前段回顾 create table 表名( 字段名1 类型[(宽度) 约束条件], 字段名2 类型[(宽度) 约束条件], 字段名3 类型[(宽度) 约束条件] ); #解释: 类型:使用限制字段必须 ...
- Linux下挂载存储设备
1. 安装iscsi (文件iscsi-initiator-utils-6.2.0.871-0.10.el5.x86_64.rpm在系统光盘可以找到) rpm -ivh iscsi-initiat ...
- OOM异常 Java内存溢出
1.OutOfMemoryError 抛出异常后先确定是堆溢出还是栈溢出 堆溢出:java.lang.OutOfMemoryError: Java heap space 堆出现OOM(标志就是Java ...
- Combo Box的简单使用(Win32)
1 SendMessage函数向窗口发送消息 LRESULT SendMessage( HWND hWnd, // handle to destination window UINT Msg, ...