博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[bzoj2809] 派遣
阅读量:6860 次
发布时间:2019-06-26

本文共 1131 字,大约阅读时间需要 3 分钟。

题意:给你一棵树,n个结点,每个点有两个权值\(a_i,b_i\),你可以选择一个结点,然后在这个结点的子树内选择一些结点,并且这些结点的\(\sum{a_i}\)小于m,则该点的贡献为\(b_i*所选结点的个数\),求最大的贡献

题解:

可并堆(斜堆)

从根dfs,维护一个当前子树的大根堆,如果子树和大于m,就一直pop权值最大的点,然后用斜堆合并即可

#include
#include
#include
#include
#include
#include
#define ll long long#define N 100010using namespace std;int n,m,tot,e_num,nxt[N],to[N],h[N],ls[N],rs[N],rt[N],a[N],b[N],v[N];ll ans,sum[N],siz[N];int gi() { int x=0,o=1; char ch=getchar(); while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar(); if(ch=='-') o=-1,ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return o*x;}void add(int x, int y) { nxt[++e_num]=h[x],to[e_num]=y,h[x]=e_num;}int merge(int x, int y) { if(!x || !y) return x+y; if(v[x]
m) { sum[u]-=v[rt[u]]; rt[u]=merge(ls[rt[u]],rs[rt[u]]);//注意2 siz[u]--; } ans=max(ans,siz[u]*b[u]);}int main() {//注意:所有有关堆的操作,一定是在新的编号上进行的,前期不熟练,建议把各种操作写成函数 n=gi(),m=gi(); for(int i=1; i<=n; i++) { int x=gi(); a[i]=gi(),b[i]=gi(); add(x,i); } dfs(1); printf("%lld", ans); return 0;}

转载于:https://www.cnblogs.com/HLXZZ/p/7638227.html

你可能感兴趣的文章
lamba表达式和匿名委托
查看>>
Sql Server系列:视图
查看>>
判断现有的类对象是哪一种类的方法
查看>>
hdu3934 凸包
查看>>
Jmeter 接口测试 响应结果中文是Unicode转为中文
查看>>
根据 plist 还原 图片
查看>>
IE8兼容问题
查看>>
03 特殊字符
查看>>
课后练习----实现窗口的切换
查看>>
this 作用域
查看>>
Python3基础03_数据类型
查看>>
JS控制文本框输入的内容
查看>>
Tomcat7后台通过get接收数据处理乱码
查看>>
python逻辑编程之kanren
查看>>
6174问题
查看>>
如何将Beyond Compare文本比较设置行的缩进
查看>>
CI路径中如何去掉index.php
查看>>
精简ICO图标可减小EXE程序文件大小
查看>>
51Nod:独木舟问题(贪心)
查看>>
第九届河南理工大学算法程序设计大赛 正式赛(部分题解)
查看>>