派遣【题解】

第一道左偏树题目,来肝一篇题解。

题目描述

在这个帮派里,有一名忍者被称之为Master。除了Master以外,每名忍者都有且仅有一个上级。为保密,同时增强忍者们的领导力,所有与他们工作相关的指令总是由上级发送给他的直接下属,而不允许通过其他的方式发送。

现在你要招募一批忍者,并把它们派遣给顾客。你需要为每个被派遣的忍者支付一定的薪水,同时使得支付的薪水总额不超过你的预算。另外,为了发送指令,你需要选择一名忍者作为管理者,要求这个管理者可以向所有被派遣的忍者发送指令,在发送指令时,任何忍者(不管是否被派遣)都可以作为消息的传递人。管理者自己可以被派遣,也可以不被派遣。当然,如果管理者没有被排遣,你就不需要支付管理者的薪水。

你的目标是在预算内使顾客的满意度最大。这里定义顾客的满意度为派遣的忍者总数乘以管理者的领导力水平,其中每个忍者的领导力水平也是一定的。

写一个程序,给定每一个忍者i的上级Bi,薪水Ci,领导力Li,以及支付给忍者们的薪水总预算M,输出在预算内满足上述要求时顾客满意度的最大值。

输入输出格式

输入格式:

第一行包含两个整数N和M,其中N表示忍者的个数,M表示薪水的总预算。

接下来N行描述忍者们的上级、薪水以及领导力。其中的第i行包含三个整数Bi,Ci,Li分别表示第i个忍者的上级,薪水以及领导力。Master满足Bi=0,并且每一个忍者的老板的编号一定小于自己的编号Bi<i。

输出格式:

输出一个数,表示在预算内顾客的满意度的最大值。

样例输入:

5 4
0 3 3
1 3 5
2 2 2
1 2 4
2 3 1

样例输出:

6

解:

  定义rt数组,记录每个忍者所在的堆;初始时,把每一个忍者都看做一个堆,然后枚举每一位忍者当领导时的薪资,判断是否大于预定薪资,如果大于,弹出对顶,直到符合标准为止。结构体里面除了维护最基本的左偏树信息,还有siz(节点数数量),sum(区间和)。用前向星存边,枚举的时候枚举每一条边即可。(记得把前向星数组开大)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#define ll long long
#define lc tr[x].l
#define rc tr[x].r
using namespace std;
const int MAXN=110010;
inline void swap(int &x,int &y){x^=y^=x^=y;}
inline int read(){
    char ch=getchar();
    int s=0,w=1;while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}return s*w;
}
int n,m,head[MAXN],nxt[MAXN],to[MAXN],tot;
struct node{
    int l,r,fa,siz,w,d;
    long long sum;
}tr[MAXN];
inline void pushup(int x){
    tr[x].sum=tr[lc].sum+tr[rc].sum+tr[x].w;
    tr[x].siz=tr[lc].siz+tr[rc].siz+1;
}
int merge(int x,int y){
    if(!x||!y)return x+y;
    if(tr[x].w<tr[y].w||(tr[x].w==tr[y].w&&x>y))swap(x,y);
    rc=merge(rc,y);
    tr[rc].fa=x;
    if(tr[lc].d<tr[rc].d)swap(lc,rc);
    tr[x].d=tr[rc].d+1;
    pushup(x);
    return x;
}
inline void add(int x,int y){
    to[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}
inline void pop(int &x){
    tr[lc].fa=tr[rc].fa=0;
    x=merge(lc,rc);
}
int rt[MAXN],id,val[MAXN];
ll ans;
void solve(int x){
    for(int i=head[x];i;i=nxt[i]){
        int u=to[i];
        solve(u);
        rt[x]=merge(rt[x],rt[u]);
    }while(rt[x]&&tr[rt[x]].sum>m)pop(rt[x]);
    ans=max(ans,val[x]*1ll*tr[rt[x]].siz);
}
int main(){
    n=read(),m=read();
    int fa,v;
    for(int i=1;i<=n;++i){
        fa=read(),v=read(),val[i]=read();
        if(fa)add(fa,i);
        tr[i].sum=tr[i].w=v;tr[i].siz=1;
        rt[i]=merge(rt[i],i);
    }solve(1);
    printf("%lld\n",ans);
    return 0;
}

 感谢 wjr dalao的指导

猜你喜欢

转载自www.cnblogs.com/h-lka/p/10779537.html