bzoj 2809 dispatching
题目大意:
一棵树中 对于一个点在子树中取一些点使这些点的权值之和$\le m$ 使选的点的数量尽量大
一个点的答案为这个尽可能大的答案$\times$这个点的第二权值 求所有点的答案的最大值
思路:
明显对于每个点的子树中选权值尽可能小的点 可以维护一个堆
维护一个可并堆 向上合并即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstring> 6 #include<cstdlib> 7 #include<queue> 8 #include<vector> 9 #include<set> 10 #include<map> 11 #define inf 2139062143 12 #define ll long long 13 #define MOD 1000000007 14 #define MAXN 100100 15 using namespace std; 16 inline int read() 17 { 18 int x=0,f=1; 19 char ch=getchar(); 20 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 21 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 22 return x*f; 23 } 24 int n,m,L[MAXN],val[MAXN],sz[MAXN],dis[MAXN],ls[MAXN],rs[MAXN],rt[MAXN]; 25 int fst[MAXN],nxt[MAXN<<1],to[MAXN<<1],cnt; 26 ll sum[MAXN],ans; 27 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;} 28 int merge(int x,int y) 29 { 30 if(!(x*y)) return x+y; 31 if(val[x]<val[y]) swap(x,y); 32 rs[x]=merge(rs[x],y); 33 if(dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]); 34 dis[x]=dis[rs[x]]+1; 35 return x; 36 } 37 void dfs(int x,int fa) 38 { 39 sz[x]=1,rt[x]=x,sum[x]=val[x]; 40 for(int i=fst[x];i;i=nxt[i]) 41 if(to[i]!=fa) 42 { 43 dfs(to[i],x); 44 sz[x]+=sz[to[i]],sum[x]+=sum[to[i]]; 45 rt[x]=merge(rt[x],rt[to[i]]); 46 } 47 while(sum[x]>m) 48 { 49 sum[x]-=val[rt[x]],sz[x]--; 50 rt[x]=merge(rs[rt[x]],ls[rt[x]]); 51 } 52 ans=max(ans,(ll)L[x]*sz[x]); 53 } 54 int main() 55 { 56 n=read(),m=read();int x; 57 for(int i=1;i<=n;i++) 58 { 59 x=read(),val[i]=read(),L[i]=read(); 60 if(x) add(i,x),add(x,i); 61 } 62 dfs(1,0);printf("%lld",ans); 63 }