1. 程式人生 > >[BZOJ2809][Apio2012]dispatching 貪心+可並堆

[BZOJ2809][Apio2012]dispatching 貪心+可並堆

數據結構 pre amp apio2012 sizeof geo typedef 基本原理 要求

題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=2809

我們考慮以每一個節點作為管理者所得的最優答案,一定是優先選擇所要薪水少的忍者。那麽首先整棵子樹的忍者都選上,如果總和大於$M$,那麽就不斷刪除薪水最大的那一個忍者。

然後考慮從下至上合並節點,我們需要一個支持合並的數據結構,就想到了啟發式合並平衡樹或者可並堆。

可並堆基本原理是維護一個$dis$,表示從根節點到達葉子節點的最短距離,要求$dis[lch]>=dis[rch]$。

 1 #include<cstdio>
 2 #include<cstring>
 3
#include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 int inline readint(){ 7 int Num;char ch; 8 while((ch=getchar())<0||ch>9);Num=ch-0; 9 while((ch=getchar())>=0&&ch<=9) Num=Num*10+ch-0; 10 return Num; 11 } 12 int N,M;
13 int C[100010],L[100010]; 14 int to[100010],ne[100010],fir[100010],cnt=0; 15 void Add(int a,int b){ 16 to[++cnt]=b; 17 ne[cnt]=fir[a]; 18 fir[a]=cnt; 19 } 20 int lch[100010],rch[100010]; 21 ll sum[100010]; 22 int siz[100010],dis[100010]; 23 ll ans=0; 24 int merge(int x,int y){ 25 if(!x||!y) return x?x:y; 26 if
(C[x]<C[y]) swap(x,y); 27 rch[x]=merge(rch[x],y); 28 if(dis[lch[x]]<dis[rch[x]]) swap(lch[x],rch[x]); 29 dis[x]=dis[rch[x]]+1; 30 sum[x]=sum[lch[x]]+sum[rch[x]]+C[x]; 31 siz[x]=siz[lch[x]]+siz[rch[x]]+1; 32 return x; 33 } 34 int Build(int x){ 35 int rt=x; 36 sum[rt]=C[x]; 37 siz[rt]=1; 38 for(int i=fir[x];i!=-1;i=ne[i]) 39 rt=merge(rt,Build(to[i])); 40 while(sum[rt]>M) 41 rt=merge(lch[rt],rch[rt]); 42 ans=max(ans,(ll)siz[rt]*L[x]); 43 return rt; 44 } 45 int main(){ 46 memset(fir,-1,sizeof(fir)); 47 N=readint(); 48 M=readint(); 49 for(int i=1;i<=N;i++){ 50 int fa=readint(); 51 C[i]=readint(); 52 L[i]=readint(); 53 Add(fa,i); 54 } 55 Build(1); 56 printf("%lld\n",ans); 57 return 0; 58 }

[BZOJ2809][Apio2012]dispatching 貪心+可並堆