Description
在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿。
在这个帮派里,有一名忍者被称之为Master。除了Master以外,每名忍者都有且仅有一个上级。为保密,同时增强忍者们的领导力,所有与他们工作相关的指令总是由上级发送给他的直接下属,而不允许通过其他的方式发送。
现在你要招募一批忍者,并把它们派遣给顾客。你需要为每个被派遣的忍者支付一定的薪水,同时使得支付的薪水总额不超过你的预算。另外,为了发送指令,你需要选择一名忍者作为管理者,要求这个管理者可以向所有被派遣的忍者发送指令,在发送指令时,任何忍者(不管是否被派遣)都可以作为消息的传递人。管理者自己可以被派遣,也可以不被派遣。当然,如果管理者没有被排遣,你就不需要支付管理者的薪水。
你的目标是在预算内使顾客的满意度最大。这里定义顾客的满意度为派遣的忍者总数乘以管理者的领导力水平,其中每个忍者的领导力水平也是一定的。
写一个程序,给定每一个忍者i的上级Bi,薪水Ci,领导力Li,以及支付给忍者们的薪水总预算M,输出在预算内满足上述要求时顾客满意度的最大值。
Input
第一行包含两个整数N和M,其中N表示忍者的个数,M表示薪水的总预算。
接下来N行描述忍者们的上级、薪水以及领导力。其中的第i行包含三个整数Bi,Ci,Li分别表示第i个忍者的上级,薪水以及领导力。Master满足Bi=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 ≤ N ≤ 100,000 忍者的个数;
1 ≤ M ≤ 1,000,000,000 薪水总预算;
0 ≤ Bi < i 忍者的上级的编号;
1 ≤ Ci ≤ M 忍者的薪水;
1 ≤ Li ≤ 1,000,000,000 忍者的领导力水平。
对于 30%的数据,N ≤ 3000。
题解
有用平衡树做的,这里给出可并堆的写法。
首先我们由贪心的思想我们可以知道:对于每个点,我们把每个以他为代表的子树里的所有点,从小到大排好序。然后一直选小的,直到不满足条件为止。
我们从叶子到根进行合并即可。用按$DFS$逆序操作。
我们将以其为根的子树放在一个按照花销为关键词的大根堆里面,一直$pop$掉堆顶,直到整个堆里面的花费$<=n$
再将这个堆中剩余的元素并到其父亲所在的堆中,继续操作。
最后统计一下答案即可。
1 #include<set> 2 #include<map> 3 #include<cmath> 4 #include<ctime> 5 #include<queue> 6 #include<stack> 7 #include<vector> 8 #include<cstdio> 9 #include<string> 10 #include<cstdlib> 11 #include<cstring> 12 #include<iostream> 13 #include<algorithm> 14 #define LL long long 15 #define RE register 16 #define IL inline 17 using namespace std; 18 const LL N=100000; 19 const LL INF=~0u>>1; 20 21 IL LL Max(const LL &a,const LL &b) {return a>b ? a:b;} 22 23 struct node 24 { 25 LL key,cost,dist; 26 node *l,*r; 27 LL ldist() {return l ? l->dist:0;} 28 LL rdist() {return r ? r->dist:0;} 29 }H[N+5],*root[N+5]; 30 LL father[N+5],sum[N+5],remain[N+5]; 31 node* Merge(node* a,node* b); 32 33 LL n,m; 34 LL b,c,l; 35 36 struct tt 37 { 38 LL to,next; 39 }edge[N+5]; 40 LL path[N+5],top; 41 IL void Add(LL u,LL v); 42 LL Rank[N+5],tail; 43 void Dfs(LL r,LL father); 44 45 int main() 46 { 47 scanf("%lld%lld",&n,&m); 48 for (RE LL i=1;i<=n;i++) 49 { 50 scanf("%lld%lld%lld",&b,&c,&l); 51 father[i]=b; 52 remain[i]=1; 53 sum[i]=H[i].cost=c; 54 H[i].key=l; 55 root[i]=H+i; 56 Add(b,i); 57 } 58 Dfs(0,0); 59 for (RE LL i=0;i<n;i++) 60 { 61 LL u=Rank[i]; 62 while (sum[u]>m) 63 { 64 sum[u]-=root[u]->cost; 65 remain[u]--; 66 root[u]=Merge(root[u]->l,root[u]->r); 67 } 68 sum[father[u]]+=sum[u]; 69 remain[father[u]]+=remain[u]; 70 root[father[u]]=Merge(root[father[u]],root[u]); 71 } 72 LL ans=-INF; 73 for (RE LL i=0;i<=n;i++) ans=Max(ans,H[i].key*remain[i]); 74 printf("%lld ",ans); 75 return 0; 76 } 77 78 IL void Add(LL u,LL v) 79 { 80 edge[++top].to=v; 81 edge[top].next=path[u]; 82 path[u]=top; 83 } 84 void Dfs(LL r,LL father) 85 { 86 for (RE LL i=path[r];i;i=edge[i].next) if (edge[i].to!=father) Dfs(edge[i].to,r); 87 Rank[tail++]=r; 88 } 89 node* Merge(node* a,node* b) 90 { 91 if (!a||!b) return a ? a:b; 92 if (a->cost<b->cost) swap(a,b); 93 a->r=Merge(a->r,b); 94 if (a->ldist()<a->rdist()) swap(a->l,a->r); 95 a->dist=a->rdist()+1; 96 return a; 97 }