点此看题面

大致题意: 有\(N\)名忍者,每名忍者有三个属性:上司\(B_i\),薪水\(C_i\)和领导力\(L_i\)。你要选择一个忍者作为管理者,然后在所有被他管理的忍者中选择若干名忍者,使薪水总和不超过预算\(M\)。现让你最大化被派遣的忍者总数乘以管理者的领导力水平。

关于左偏树

这道题是一道比较裸的左偏树板子题。

左偏树,主要用途是实现堆的合并,在这一类的题目中还是比较实用的。

大致思路

如果你会左偏树,那么这题就是一道水题。

首先考虑遍历题目中给出的树,然后对每一个节点开一个大根堆,每次把超过预算的多余部分弹出,更新\(ans\)之后再与父亲的堆进行合并。

一个细节就是当前节点可能会被弹出,所以我们要用\(Top_x\)来记录当前节点堆的堆顶,然后对\(Top_x\)进行操作。

代码

#include<bits/stdc++.h>
#define N 100000
#define swap(x,y) (x^=y^=x^=y)
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
#define Gmax(x,y) (x<(y)&&(x=(y)))
#define LL long long
using namespace std;
int n,m,ee=0,lnk[N+5],Top[N+5],cnt[N+5],Cost[N+5],Val[N+5];LL ans=0,tot[N+5];
struct edge
{
int to,nxt;
}e[N+5];
class FIO
{
private:
#define Fsize 100000
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
#define pc(ch) (void)(putchar(ch))
int Top,FoutSize;char ch,*A,*B,Fin[Fsize],Fout[Fsize],Stack[Fsize];
public:
inline void read(int &x) {x=0;while(!isdigit(ch=tc()));while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));}
inline void write(LL x) {if(!x) return pc('0');while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);}
}F;
class Class_LeftistTree//左偏树模板
{
private:
struct Tree
{
int Val,Dis,Exist,Father,Son[2];
Tree(int x=0):Val(x){Dis=Father=Son[0]=Son[1]=0,Exist=1;}
}node[N+5];
inline int Merge(int x,int y)
{
if(!x||!y) return x+y;
if(node[x].Val<node[y].Val) swap(x,y);
if(node[node[x].Son[1]=Merge(node[x].Son[1],y)].Father=x,node[node[x].Son[0]].Dis<node[node[x].Son[1]].Dis) swap(node[x].Son[0],node[x].Son[1]);
return node[x].Dis=node[node[x].Son[1]].Dis+1,x;
}
inline int TopPos(int x) {while(node[x].Father) x=node[x].Father;return x;}
public:
Class_LeftistTree() {node[0].Dis=-1,node[0].Exist=0;}
inline void Init(int n,int *data) {for(register int i=1;i<=n;++i) node[i]=Tree(data[i]);}
inline void Union(int x,int y) {if((x=TopPos(x))^(y=TopPos(y))&&node[x].Exist&&node[y].Exist) Merge(x,y);}
inline int PopTop(int x) {return node[x=TopPos(x)].Val=node[x].Dis=-1,node[x].Exist=0,node[node[x].Son[0]].Father=node[node[x].Son[1]].Father=0,Merge(node[x].Son[0],node[x].Son[1]);}
inline int TopVal(int x) {return node[TopPos(x)].Val;}
}LeftistTree;
inline void dfs(int x)//遍历
{
register int i;
for(i=lnk[Top[x]=x],tot[x]=Cost[x],cnt[x]=1;i;i=e[i].nxt) dfs(e[i].to),LeftistTree.Union(x,Top[e[i].to]),tot[x]+=tot[e[i].to],cnt[x]+=cnt[e[i].to];//先遍历子节点,然后从子节点更新信息
while(tot[x]>m) tot[x]-=LeftistTree.TopVal(Top[x]),--cnt[x],Top[x]=LeftistTree.PopTop(Top[x]);//弹出多余的元素
Gmax(ans,1LL*Val[x]*cnt[x]);//更新ans
}
int main()
{
register int i,x,rt;
for(F.read(n),F.read(m),i=1;i<=n;++i) F.read(x),F.read(Cost[i]),F.read(Val[i]),(x?add(x,i):rt=i);
return LeftistTree.Init(n,Cost),dfs(rt),F.write(ans),0;
}

【BZOJ2809】[APIO2012] dispatching(左偏树例题)的更多相关文章

  1. bzoj2809 [Apio2012]dispatching(左偏树)

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

  2. bzoj2809 [Apio2012]dispatching——左偏树(可并堆)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2809 思路有点暴力和贪心,就是 dfs 枚举每个点作为管理者: 当然它的子树中派遣出去的忍者 ...

  3. 【bzoj2809】[Apio2012]dispatching 左偏树

    2016-05-31  15:56:57 题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2809 直观的思想是当领导力确定时,尽量选择薪水少的- ...

  4. [Apio2012]dispatching 左偏树

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

  5. [Apio2012]dispatching 左偏树做法

    http://codevs.cn/problem/1763/ 维护子树大根堆,当子树薪水和>m时,删除最贵的点 #include<cstdio> #include<iostre ...

  6. APIO2012 派遣dispatching | 左偏树

    题目链接:戳我 就是尽可能地选取排名小的,加起来就可以了.然后我们考虑利用一个大根堆,一个一个合并,如果超过派遣的钱,我们就把费用最大的那个忍者丢出队列. 左偏树,作为一个十分优秀的可并堆,我们这道题 ...

  7. BZOJ2809 dispatching(左偏树)

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

  8. [APIO2012]派遣 左偏树

    P1552 [APIO2012]派遣 题面 考虑枚举每个节点作为管理者,计算所获得的满意程度以更新答案.对于每个节点的计算,贪心,维护一个大根堆,每次弹出薪水最大的人.这里注意,一旦一个人被弹出,那么 ...

  9. 洛谷P1552 [APIO2012] 派遣 [左偏树,树形DP]

    题目传送门 忍者 Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都 ...

随机推荐

  1. PAT L3-010【完全二叉树】

    静态建树判一下1-n是不是为空就好了,如果有空的  就说明不是complete binary tree (和线段树建树差不多啊)Left=2*root:Right=2*root+1 #include ...

  2. Cogs 6. 线型网络

    6. 线型网络 ★★☆   输入文件:linec.in   输出文件:linec.out   简单对比时间限制:1 s   内存限制:256 MB [问题描述] 有 N(N<=20)台 PC 放 ...

  3. 【NOIP模拟赛】收银员(一道差分约束好题)

    /* s[]表示最优方案的序列中的前缀和,那么s[23]就是最优方案 由题意我们可以列出这样一些式子: s[i]+s[23]-s[16+i]>=a[i] (i-8<0) s[i]-s[i- ...

  4. ORM(一)

    ORM常识: 1.一对多,多的一方设置外键字段,有外键字段的表叫做子表.没有外键字段的表叫做主表. 2.主表放到子表的下面,否则子表找不到主表,写数据要先往主表中写. 数据库:(1)不创建主键,会自动 ...

  5. git 脚本

    echo $PWD message=$1 content='.' if [ ! -n "$1" ] ;then message=`date` message=$message' 推 ...

  6. Draw a Mess (并查集)

    It's graduated season, every students should leave something on the wall, so....they draw a lot of g ...

  7. 浅谈ThreadLocal模式

    一.前言: ThreadLocal模式,严格意义上不是一种设计模式,而是java中解决多线程数据共享问题的一个方案.ThreadLocal类是java JDK中提供的一个类,用来解决线程安全问题,并不 ...

  8. 打印BroadcastReceiver的所有接受者

    Android中收到短信等事件都是通过广播发送给应用程序的,手机卫士等程序都是通过注册高优先级的BroadcastReceiver来实现短信防火墙等功能.对于我们来说很想知道系统中都有哪些程序注册了B ...

  9. 二维hash

    题目描述 给出一个n * m的矩阵.让你从中发现一个最大的正方形.使得这样子的正方形在矩阵中出现了至少两次.输出最大正方形的边长. 输入描述: 第一行两个整数n, m代表矩阵的长和宽: 接下来n行,每 ...

  10. C# String.Format方法

    一.定义String.Format是将指定的 String类型的数据中的每个格式项替换为相应对象的值的文本等效项. 如: (1)string p1 = "Jackie";strin ...