2809: [Apio2012]dispatching

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit:
2334  Solved: 1192
[Submit][Status][Discuss]

Description

在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿。在这个帮派里,有一名忍者被称之为 Master。除了 Master以外,每名忍者都有且仅有一个上级。为保密,同时增强忍者们的领导力,所有与他们工作相关的指令总是由上级发送给他的直接下属,而不允许通过其他的方式发送。现在你要招募一批忍者,并把它们派遣给顾客。你需要为每个被派遣的忍者
支付一定的薪水,同时使得支付的薪水总额不超过你的预算。另外,为了发送指令,你需要选择一名忍者作为管理者,要求这个管理者可以向所有被派遣的忍者
发送指令,在发送指令时,任何忍者(不管是否被派遣)都可以作为消息的传递
人。管理者自己可以被派遣,也可以不被派遣。当然,如果管理者没有被排遣,就不需要支付管理者的薪水。你的目标是在预算内使顾客的满意度最大。这里定义顾客的满意度为派遣的忍者总数乘以管理者的领导力水平,其中每个忍者的领导力水平也是一定的。写一个程序,给定每一个忍者
i
的上级
B
i薪水Ci领导力L
i
以及支付给忍者们的薪水总预算 M,输出在预算内满足上述要求时顾客满意度的最大值。
1  ≤N ≤ 100,000 忍者的个数;
1  ≤M ≤ 1,000,000,000 薪水总预算; 
0  ≤Bi < i  忍者的上级的编号;
1
 ≤Ci ≤ M                     忍者的薪水;
1
 ≤Li ≤ 1,000,000,000             忍者的领导力水平。

Input

从标准输入读入数据。
第一行包含两个整数 N M,其中 N表示忍者的个数,M表示薪水的总预算。
接下来 N行描述忍者们的上级、薪水以及领导力。其中的第 i 行包含三个整 Bi , C i , L
i
分别表示第i个忍者的上级,薪水以及领导力Master满足B i =
0
并且每一个忍者的老板的编号一定小于自己的编号
Bi < i

Output

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

Sample Input

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

Sample Output

6

HINT

如果我们选择编号为 1的忍者作为管理者并且派遣第三个和第四个忍者,薪水总和为
4,没有超过总预算4。因为派遣了2个忍者并且管理者的领导力为3,
用户的满意度为6,是可以得到的用户满意度的最大值。

Source

Solution

Splay+启发式合并

题目可能有点不太好懂,反正我一开始没看懂

学术一点的大意就是:给定一棵树,每个点有一个C值和一个L值,求一个点u和一个点集S,使得S里面的点都在u为根的这课子树上,S里面所有点的C值和小于等于m,并且L[u] * |S|最大。

那么就好想多了,首先对于薪水的总和是有限制的,那么很显然,要使得 派遣的人数最多 即,一棵子树中,最小的几个的

那么用Splay去维护即可,维护sum,用C去辅助查找和插入;

因为上级编号一定小于下级,从n~1倒序合并即可。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define maxn 110010
struct data{int next,to;}edge[maxn];int head[maxn],cnt;
void add(int u,int v){cnt++;edge[cnt].next=head[u];head[u]=cnt;edge[cnt].to=v;} int n,m,q;int que[maxn];
int root,sz;
int fa[maxn],son[maxn][],Li[maxn],Ci[maxn],size[maxn];long long sumc[maxn];
int get(int now){return son[fa[now]][]==now;}
void update(int now)
{
if (!now) return;
size[now]=+size[son[now][]]+size[son[now][]];
sumc[now]=sumc[son[now][]]+sumc[son[now][]]+Ci[now];
}
void rotate(int &now)
{
int old=fa[now],oldf=fa[old],which=get(now);
son[old][which]=son[now][which^]; fa[son[old][which]]=old;
fa[old]=now; son[now][which^]=old; fa[now]=oldf;
if (oldf) son[oldf][son[oldf][]==old]=now;
update(old); update(now);
}
void splay(int &now)
{
for (int f; (f=fa[now]); rotate(now))
if (fa[f])
if (get(now)==get(f))
rotate(f); else rotate(now);
}
void insert(int x,int rt)
{
int y=rt,last=;
while (y){
last=y;
if (Ci[x]>Ci[y]) y=son[y][];
else y=son[y][];
}
fa[x]=last; son[last][(Ci[x]>Ci[last])]=x;
update(x); update(last);
splay(x);
}
void merge(int u,int v)
{
splay(u);splay(v);
if (size[u]>size[v]) swap(u,v);
int he=,ta=,last=v;
que[]=u;
while (he<ta)
{
int x = que[++he];
if (son[x][]) que[++ta]=son[x][];
if (son[x][]) que[++ta]=son[x][];
son[x][]=son[x][]=;
}
for (int i=; i<=ta; i++) insert(que[i],last),last=que[i];
}
int ask(int rt,int k)
{
if (!rt) return ;
if (sumc[son[rt][]]+Ci[rt]==k) return size[son[rt][]]+;
if (sumc[rt]<=k) return size[rt];
if (sumc[son[rt][]]+Ci[rt]>k) return ask(son[rt][],k);
else return size[son[rt][]]++ask(son[rt][],k-(sumc[son[rt][]]+Ci[rt]));
}
int main()
{
n=read(),m=read();
for (int i=; i<=n; i++)
{
int x=read();Ci[i]=read();Li[i]=read();
sumc[i]=Ci[i]; size[i]=;
if (!x) root=x; else add(x,i);
}
long long ans=;
for (int i=n; i>; i--)
{
for (int j=head[i]; j; j=edge[j].next)
merge(edge[j].to,i);
splay(i);
ans=max(ans,(long long)Li[i]*ask(i,m));
}
printf("%lld\n",ans);
return ;
}

讲道理,一开始T掉了...调了一会..发现自己insert有点小问题,修改了一下,删除调试信息的时候多删了一句...害的我又多调了好久.....

【BZOJ-2809】dispatching派遣 Splay + 启发式合并的更多相关文章

  1. BZOJ 3545: [ONTAK2010]Peaks [Splay启发式合并]

    3545: [ONTAK2010]Peaks 题意:带权图,多组询问与一个点通过边权\(\le x\)的边连通的点中点权k大值 又读错题了,输出点一直WA,问的是点权啊 本题加强版强制在线了,那这道题 ...

  2. BZOJ 2733: [HNOI2012]永无乡 [splay启发式合并]

    2733: [HNOI2012]永无乡 题意:加边,询问一个连通块中k小值 终于写了一下splay启发式合并 本题直接splay上一个节点对应图上一个点就可以了 并查集维护连通性 合并的时候,把siz ...

  3. 【BZOJ-2733】永无乡 Splay+启发式合并

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2048  Solved: 1078[Submit][Statu ...

  4. BZOJ2733 永无乡【splay启发式合并】

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  5. bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)

    这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并. 好爽!!! 写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子...),调了好久好久,过了样例, ...

  6. 【BZOJ2733】永无乡[HNOI2012](splay启发式合并or线段树合并)

    题目大意:给你一些点,修改是在在两个点之间连一条无向边,查询时求某个点能走到的点中重要度第k大的点.题目中给定的是每个节点的排名,所以实际上是求第k小:题目求的是编号,不是重要度的排名.我一开始差点被 ...

  7. 算法复习——splay+启发式合并(bzoj2733-永无乡)

    题目: Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通 ...

  8. 【BZOJ2809】【splay启发式合并】dispatching

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

  9. 【BZOJ 2733】【HNOI 2012】永无乡 Splay启发式合并

    启发式合并而已啦,, 调试时发现的错误点:insert后没有splay,把要拆开的树的点插入另一个树时没有把ch[2]和fa设为null,找第k大时没有先减k,,, 都是常犯的错误,比赛时再这么粗心就 ...

随机推荐

  1. Android应用中菜单(Menu)的位置显示问题

    http://blog.csdn.net/songjinshi/article/details/17381245 注意:为了适配4.0菜单能够横向显示,建议在activity中添加android:th ...

  2. java 20 - 6 加入了异常处理的字节输出流的操作

    昨天坐了十几个钟的车回家,累弊了.... ————————————割掉疲劳————————————— 前面的字节输出流都是抛出了异常不管,这次的加入了异常处理: 首先还是创建一个字节输出流对象,先给它 ...

  3. java 15-4 集合的专用遍历工具 迭代器

    Iterator iterator():迭代器,集合的专用遍历方式 A:Object next():获取元素,并移动到下一个位置. 有时候会出现这样的错误: NoSuchElementExceptio ...

  4. 书籍推荐 《移动Web手册》 奇舞团

    书籍推荐  <移动Web手册> 奇舞团

  5. 第三方登录 ----转载自简书,作者 <<碧霄问鼎>>

    这几天遇到一个需求:做第三方登录和分享.遇到了一些坑,把整个过程整理记录下来,方便他人,同时也捋一下思路. 当时考虑过把每个平台的SDK下载下来,一个一个弄,一番取舍后决定还是用ShareSDK.这里 ...

  6. center

    center标签对其包围的文本进行水平居中处理

  7. 【MySQL】Linux MySQL学习记录

    1.查看日志存放路径 show variables like 'general_log_file'; 2.查看日志是否开启 show global variables like 'log_bin%'; ...

  8. [CareerCup] 13.4 Depp Copy and Shallow Copy 深拷贝和浅拷贝

    13.4 What is the difference between deep copy and shallow copy? Explain how you would use each. 这道题问 ...

  9. LeetCode 笔记22 Distinct Subsequences 动态规划需要冷静

    Distinct Subsequences Given a string S and a string T, count the number of distinct subsequences of  ...

  10. iOS项目重构日记

    如何重构 首先,要对程序的一般架构烂熟于心,尤其是MVC,这是基本.还有就是分离存储和网络请求的逻辑. 对于一些常用的控件尽量分离复用,设置开关函数,适当的时候开启,不要的时候关闭,有必要的话还可以 ...