bzoj 2809 dispatching

题目大意:

一棵树中 对于一个点在子树中取一些点使这些点的权值之和$\le m$ 使选的点的数量尽量大

一个点的答案为这个尽可能大的答案$\times$这个点的第二权值 求所有点的答案的最大值

思路:

明显对于每个点的子树中选权值尽可能小的点 可以维护一个堆

维护一个可并堆 向上合并即可

 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 }
View Code

 

posted @ 2018-11-07 09:05  jack_yyc  阅读(95)  评论(0编辑  收藏  举报