贪心/可并堆
跪了……我这么弱果然还是应该回家种红薯去……
考虑选人的时候,每个人对答案的贡献其实是一样的,都是1,那么我们就贪心地去选花钱少的就好啦~
具体的做法:倒着枚举(因为有b[i]<i),考虑选第 i 个人做领导者的时候,以他为根的子树中如果花费>m,那么我们就踢掉花钱最多的人,直到sum<m,用l[i]*num[i]更新答案(num[i]表示以 i 为根的子树中选了多少人),然后把这棵子树的堆并到他的父亲的堆中去(初始每个人的堆都只有他自己)
或许你看看代码更容易理解一点……
总之就是枚举领导者,属下能多选就多选,不能选的时候踢掉花钱最多的那个
当然这题只要是支持快速合并以及删除最大值的数据结构都可以的……比如用splay/treap+启发式合并也可以捉,嗯我写的是左偏树……
1 /************************************************************** 2 Problem: 2809 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:948 ms 7 Memory:7528 kb 8 ****************************************************************/ 9 10 //BZOJ 2809 11 #include<vector> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 inline int getint(){ 23 int v=0,sign=1; char ch=getchar(); 24 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 25 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 26 return v*sign; 27 } 28 const int N=100010,INF=~0u>>2; 29 typedef long long LL; 30 /******************tamplate*********************/ 31 LL n,m,b[N],c[N],l[N],rt[N]; 32 LL ans=0; 33 struct node{ 34 int v,l,r,dis,f,num; LL sum; 35 node(int v=0,int l=0,int r=0,int dis=0, 36 int f=0,int num=0,LL sum=0): 37 v(v),l(l),r(r),dis(dis), 38 f(f),num(num),sum(sum){} 39 }; 40 struct Left_tree{ 41 node t[N]; 42 int merge(int x,int y){ 43 if(!x||!y) return x?x:y; 44 if (t[x].v<t[y].v) swap(x,y); 45 t[x].r=merge(t[x].r,y); 46 // t[t[x].r].f=x; 47 if (t[t[x].l].dis<t[t[x].r].dis) swap(t[x].l,t[x].r); 48 if (t[x].r==0) t[x].dis=0; 49 else t[x].dis=t[t[x].r].dis+1; 50 t[x].sum=t[t[x].l].sum+t[t[x].r].sum+t[x].v; 51 t[x].num=t[t[x].l].num+t[t[x].r].num+1; 52 return x; 53 } 54 int pop(int x){ 55 int l=t[x].l,r=t[x].r; 56 // t[l].f=l; t[r].f=r; 57 t[x].l=t[x].r=t[x].dis=0; 58 return merge(l,r); 59 } 60 void init(){ 61 n=getint();m=getint(); 62 F(i,1,n){ 63 b[i]=getint(); 64 t[i].sum=t[i].v=getint(); 65 l[i]=getint(); 66 67 t[i].num=1; 68 rt[i]=i; 69 } 70 D(i,n,1){ 71 while(t[rt[i]].sum>m) rt[i]=pop(rt[i]); 72 if (t[rt[i]].num*l[i]>ans) ans=t[rt[i]].num*l[i]; 73 if (rt[i] && b[i]) rt[b[i]]=merge(rt[b[i]],rt[i]); 74 } 75 printf("%lld ",ans); 76 } 77 }H; 78 int main(){ 79 #ifndef ONLINE_JUDGE 80 freopen("2809.in","r",stdin); 81 freopen("2809.out","w",stdout); 82 #endif 83 H.init(); 84 return 0; 85 }