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的更多相关文章

  1. BZOJ - 2809 dispatching 主席树+dfs序

    在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都有且仅有一个上级.为保密,同时增强忍者们的 ...

  2. 【BZOJ 2809 dispatching】

    Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 4393  Solved: 2246[Submit][Status][Discuss] Descript ...

  3. BZOJ 2809: [Apio2012]dispatching( 平衡树 + 启发式合并 )

    枚举树上的每个结点做管理者, 贪心地取其子树中薪水较低的, 算出这个结点为管理者的满意度, 更新答案. 用平衡树+启发式合并, 时间复杂度为O(N log²N) ------------------- ...

  4. bzoj 2809: [Apio2012]dispatching -- 可并堆

    2809: [Apio2012]dispatching Time Limit: 10 Sec  Memory Limit: 128 MB Description 在一个忍者的帮派里,一些忍者们被选中派 ...

  5. 【BZOJ 2809】2809: [Apio2012]dispatching (左偏树)

    2809: [Apio2012]dispatching Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Maste ...

  6. AC日记——dispatching bzoj 2809

    2809: [Apio2012]dispatching Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3290  Solved: 1740[Submi ...

  7. BZOJ 2809 APIO2012 dispatching Treap+启示式合并 / 可并堆

    题目大意:给定一棵树,选定一棵子树中的一些点,薪水和不能超过m,求点的数量*子树根节点的领导能力的最大值 考虑对于每一个节点,我们维护一种数据结构,在当中贪心寻找薪金小的雇佣. 每一个节点暴力重建一定 ...

  8. BZOJ 2809: [Apio2012]dispatching(左偏树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=2809 题意: 思路:最简单的想法就是枚举管理者,在其子树中从薪水低的开始选起,但是每个节点都这样处理 ...

  9. BZOJ 2809 [Apio2012]dispatching(斜堆+树形DP)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2809 [题目大意] 给出一棵树,求出每个点有个权值,和一个乘算值,请选取一棵子树, 并 ...

随机推荐

  1. C语言一些常用的功能

    1.测试运行时间: #include<stdio.h> #include<stdlib.h> #include<time.h> int main() { clock ...

  2. bzoj 5093 [Lydsy1711月赛]图的价值 NTT+第二类斯特林数

    [Lydsy1711月赛]图的价值 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 245  Solved: 128[Submit][Status][D ...

  3. hadoop删除节点和添加节点

    从hadoop移除机器把需要移除的机器增加到exclueds文件中,强制刷新datanode列表,等待decommission 状态正常后,即可停机下架,如有必要在namenode执行balancer ...

  4. 转:RBAC权限控制

    名词解释: RBAC:Role-Based Access Control,基于角色的访问控制   关键词: RBAC,Java Shiro,Spring Security,   一. RBAC 要解决 ...

  5. jQuery通过CSS()方法给指定的元素同时设置多个样式

    <!DOCTYPE html> <html> <head> <script src="http://ajax.googleapis.com/ajax ...

  6. php中的split函数

    字符串分割函数:split函数 <?php $email='microsoft@exam!ple.com'; $domain = split('\.|@|!',$email);//split分割 ...

  7. python 匿名函数和递归函数

    匿名函数lambda 匿名函数:lambda  x,y:x+y 上述解释:x,y分别是函数的参数,x+y是函数的返回值 匿名函数的命名规则,用lamdba 关键字标识,冒号(:)左侧表示函数接收的参数 ...

  8. 视频图像处理基础知识5(RGB与Ycbcr相互转换公式 )【转】

    转自:http://blog.csdn.net/Times_poem/article/details/51471438 版权声明:本文为博主原创文章,未经博主允许不得转载. 需求说明:视频处理算法基本 ...

  9. springmvc Converter

    以下,来自于Springmvc指南第二版,第93页. Spring的Converter是可以将一种类型转为另一种类型. 例如用户输入的date类型可能有多种格式. 比如:在controller中接收一 ...

  10. C# 正则表达式判断IP,URL等及其解释

    C# 正则表达式判断IP,URL等及其解释 判断IP格式方法: public static bool ValidateIPAddress(string ipAddress) { Regex valid ...