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. Faster R-CNN教程

    Faster R-CNN教程 最后更新日期:2016年4月29日 本教程主要基于python版本的faster R-CNN,因为python layer的使用,这个版本会比matlab的版本速度慢10 ...

  2. QT QLayout 清空

    QLayout* pLayout = (QLayout*)ui->frame->layout(); )) { QWidget* pWidget = child->widget(); ...

  3. 3中转换JSON数据的方式

    一:前言 来公司一个星期,把最近做的东西梳理下,并把觉得有必要的知识点记载下,现在传数据很多都是用JSON来传数据,所以我就找了集中传json的方式,其实是有五种的,但是有一个我没有用过,太陌生了,上 ...

  4. HDU1099---数学 | 思维

    hdu 1099 Lottery题意:1~n编号的彩票,要买全,等概率条件下平均要买几张.已经买了m张时,买中剩下的概率为1-m/n,则要买的张数为1/(1-m/n)n=2,s=1+1/(1-1/2) ...

  5. php session 阻塞 过期不自动清除session文件

     php默认session session_start后,php就会打开session文件,然后同一时间用户再用那个session_id访问,就会被前面那个请求阻塞直到前面一个访问结束才会释放文件在使 ...

  6. [bzoj1009][HNOI2008]GT考试——KMP+矩阵乘法

    Brief Description 给定一个长度为m的禁止字符串,求出长度为n的字符串的个数,满足: 这个字符串的任何一个字串都不等于给定字符串. 本题是POJ3691的弱化版本. Algorithm ...

  7. [bzoj1015][JSOI2008]星球大战——并查集+离线处理

    题解 给定一张图,支持删点和询问连通块个数 按操作顺序处理的话要在删除点的同时维护图的形态(即图具体的连边情况),这是几乎不可做的 我们发现,这道题可以先读入操作,把没删的点的边先连上,然后再倒序处理 ...

  8. bzoj 1297 矩阵乘法变形

    首先对于矩阵乘法的功能有很多,记得有篇论文叫矩阵乘法在信息学竞赛中的应用,里面详细介绍了矩阵的 作用 其中一个就是求图的固定时间方案数,也就是给定一张图,每两个点之间由一条边长为1的边相连, 求任意两 ...

  9. hdu 3003 Pupu

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3003 题目大意:一种动物身上有n种不同的皮肤,每种皮肤有透明很不透明两种状态,经过一天的日晒,透明的可 ...

  10. django返回二进制图片

    @login_required def down_img(request, path): content = Storage().download(path) from django.http imp ...