您的位置:首页 > 其它

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

2015-03-12 16:25 267 查看

Description

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

[align=left]1 ≤N ≤ 100,000 忍者的个数;[/align]
[align=left]1 ≤M ≤ 1,000,000,000 薪水总预算; [/align]
[align=left] [/align]
[align=left]0 ≤Bi < i 忍者的上级的编号;[/align]

[align=left]1 ≤Ci ≤ M 忍者的薪水;[/align]
[align=left]1 ≤Li ≤ 1,000,000,000 忍者的领导力水平。[/align]

Input

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

Output

[align=left]输出一个数,表示在预算内顾客的满意度的最大值。[/align]
[align=left] [/align]
[align=left] [/align]

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,

用户的满意度为 2 ,是可以得到的用户满意度的最大值。

Source

【分析】

什么启发式合并。叫得这么高端...不就是一个个插进去吗....

记得要用longlong

发现了一个很严重的问题,昨天的splay里面有问题。。

还是指针的问题....如果没有用引用的话就要返回,否则的话值不会变,貌似这个问题只有在以大小作为排序标准的情况下才会出现?

因为好像splay处理序列的时候一般是不需要根据大小排序的,所以一直没有发现....还好发现了,不然省选出现这个问题就跪了啊!!

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <utility>
#include <iomanip>
#include <string>
#include <cmath>
#include <queue>
#include <assert.h>
#include <map>
#include <ctime>
#include <cstdlib>
#include <stack>
#define LOCAL
const int MAXN = 1020000 + 10;
const int INF = 100000000;
const int SIZE = 450;
const int maxnode =  0x7fffffff + 10;
using namespace std;
vector<long long>G[MAXN];
stack<long long>S;
long long n;
long long b[MAXN];
long long c[MAXN], l[MAXN], m;

struct SPLAY{
struct Node{
long long size;
long long val, sum;
Node *parent, *ch[2];

long long cmp(){
if (parent->ch[0] == this) return 0;
else return 1;
}
}*nil, _nil, mem[MAXN], *root[MAXN];
long long tot, pos;//pos表示当前根是哪一个

void update(Node *&t){
if (t == nil) return;
t->size = 1;
t->size += t->ch[0]->size + t->ch[1]->size;
t->sum = t->val;
t->sum += t->ch[0]->sum + t->ch[1]->sum;
return;
}
void init(){
//循环哨兵
nil = &_nil;
_nil.val = _nil.size =_nil.sum = 0;
_nil.parent = _nil.ch[0] = _nil.ch[1] = nil;

tot = 0;
//没有根就只能加一点特判断了
}
Node *NEW(long long val){
Node *p = &mem[tot++];
p->size = 1;
p->val = p->sum = val;
p->parent = p->ch[0] = p->ch[1] = nil;
return p;
}
//旋转,d代表1右旋
void Rotate(Node *t, long long d){
Node *p = t->parent;
t = p->ch[d ^ 1];
p->ch[d ^ 1] = t->ch[d];
if (t->ch[d] != nil) t->ch[d]->parent = p;
t->ch[d] = p;
t->parent = p->parent;
//注意不是引用
if (t->parent != nil){
if (t->parent->ch[0] == p) t->parent->ch[0] = t;
else t->parent->ch[1] = t;
}
p->parent = t;
if (t->parent == nil) root[pos] = t;
update(p);
update(t);
}
//没标记就是好TAT
Node* splay(Node *x, Node *y){
while (x->parent != y){
if (x->parent->parent == y){
Rotate(x, x->cmp() ^ 1);
break;
}else{
Rotate(x->parent, x->parent->cmp() ^ 1);
Rotate(x, x->cmp() ^ 1);
}
update(x);
}
update(x);
return x;
}
void insert(Node *&t, long long val){
if (t == nil){
t = NEW(val);
return;
}
Node *x = t;
Node *y = t;
while (1){
long long d = (val >= x->val);
if (x->ch[d] == nil){
x->ch[d] = NEW(val);
x->ch[d]->parent = x;
//update(x);
t = splay(x->ch[d], nil);
return;
}else {x = x->ch[d];}
}
return;//不用update
}
void push(Node *&t){
if ( t == nil) return;
push(t->ch[1]);
S.push(t->val);
push(t->ch[0]);
}
//感动天地没有find!
Node* merge(Node *a, Node *b, long long pa, long long pb){
if (a == nil) return b;
else if (b == nil) return a;
//注意是将b插入a,为了启发式合并要判断大小
if (a->size < b->size){
//swap(root[pa], root[pb]);
swap(a, b);
}
push(b);//把p推到栈里面
while (!S.empty()){
insert(a, S.top());
S.pop();
}
//delete b;//可以删掉吧....
return a;
}

//表示在Node*t中sum比m小
long long get(Node *t, long long val){
Node *x = t;
long long cnt = 0;
while (1){
if (x == nil) break;
if (val >= x->sum) {cnt += x->size; break;}//一次性全部拿完,包括子树
//能往左走当然尽量往左
long long tmp = (x->ch[0]->sum);
//拿完左子树去右边拿
if (val >= (tmp + x->val)) {cnt += x->ch[0]->size + 1; val -= tmp + x->val; x = x->ch[1];}
else x = x->ch[0];//往左边拿
}
return cnt;
}
void work(){
init();
while (!S.empty()) S.pop();
long long Ans = 0;
for (long long i = n; i >= 1; i--){
if (G[i].size() == 0){//叶子节点
root[i] = NEW(c[i]);
if (c[i] <= m) Ans = max(Ans, l[i]);
continue;
}
if (i == 3){
//prlong long(root[8]);
//printf("\n\n\n");
}
root[i] = nil;//枚举每个管理者
pos = i;
insert(root[i], c[i]);
for (long long j = 0; j < G[i].size(); j++){
long long v = G[i][j];
root[i] = merge(root[i], root[G[i][j]], i, v);
if (i == 3){
// prlong long(root[3]);
//printf("\n\n\n");
}
}
//printf("%d\n", tot);
//if ((get(root[i], m) * l[i]) == 12)
//printf("");
if (i == 8){
//printf("%d", root[3]->size);
//prlong long(root[8]);
}
Ans = max(Ans, get(root[i], m) * l[i]);
}
/*pos = n;
insert(root
, 10);
insert(root
, 1);*/
printf("%lld\n", Ans);
//printf("%d", tot);
}
/*void print(Node *t){
if (t == nil) return ;
prlong long(t->ch[0]);
printf("%lld %lld\n", t->val, t->parent->val);
prlong long(t->ch[1]);
}*/
void debug(){
init();
Node *p = NEW(5);
insert(p, 3);
printf("%lld", p->val);
}
}A;

void read(){
//memest
long long sum = 0;
scanf("%lld%lld", &n, &m);//m为薪水总预算
for (long long i = 1; i <= n; i++){
//分别代表上级薪水领导力
scanf("%lld%lld%lld", &b[i], &c[i], &l[i]);
G[b[i]].push_back(i);
//sum += c[i];
//printf("%d %lld %d\n", b[i], c[i], (2568 / 428));
}
//第3个有6个
//printf("%d\n", m);
}

int main(){

read();
A.work();
//A.debug();
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: