BZOJ 2809 [Apio2012]dispatching(斜堆+树形DP)
2024-09-04 18:05:24
【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2809
【题目大意】
给出一棵树,求出每个点有个权值,和一个乘算值,请选取一棵子树,
并在这个子树上选择一些节点,使得根节点的乘算值乘上选取的节点数价值最大,
并且权值和不超过给定的限制
【题解】
我们在树上做dfs,计算每个点作为子树根节点时候的价值,
维护可并的权值大根堆,自下而上合并,当发现权值和大于限制的时候pop根节点即可。
【代码】
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int N=100010;
int x,n,m,cnt,tot;
vector<int> v[N];
LL ans,sum[N],size[N];
int C[N],L[N],root[N];
struct SHeap{
int v[N],l[N],r[N];
int merge(int x,int y){
if(x==0||y==0)return x+y;
if(v[x]<v[y])swap(x,y);
r[x]=merge(r[x],y);
swap(l[x],r[x]);
return x;
}void pop(int &x){x=merge(l[x],r[x]);}
int top(int x){return v[x];}
}heap;
void dfs(int x){
root[x]=++tot; heap.v[tot]=C[x];
size[x]=1; sum[x]=C[x];
for(int i=0;i<v[x].size();i++){
dfs(v[x][i]);
sum[x]+=sum[v[x][i]];
size[x]+=size[v[x][i]];
root[x]=heap.merge(root[x],root[v[x][i]]);
}
while(sum[x]>m){
sum[x]-=heap.top(root[x]);
heap.pop(root[x]);
size[x]--;
}ans=max(ans,size[x]*L[x]);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&x,&C[i],&L[i]);
v[x].push_back(i);
}dfs(1);
printf("%lld\n",ans);
return 0;
}
最新文章
- 如果没有Visual Studio 2015,我们如何创建.NET Core项目 ?
- PBOC金融IC卡,卡片与终端交互的13个步骤,简介-第二组(转)
- LayoutInflater的infalte()
- java的分层开发
- 21. Clone Graph
- PHP 错误与异常 笔记与总结(6)将错误日志保存在系统日志中
- Qt之事件系统
- JavaScript 三种绑定事件方式之间的区别
- Webx常用接口
- hibernate.cfg.xml配置(Oracle+c3p0)
- Unsupported major.minor version 52.0 处理方式
- AFURLRequestSerialization
- zookeeper curator处理会话过期session expired
- python 网络爬虫与信息提取 学习笔记day4
- JAVA应用程序转换为Applet
- Go指南练习_斐波纳契闭包
- aspose 小记
- matlab中将矩阵按照行打乱顺序的一个例子
- Redis批量查询删除KEYS
- umount 强制卸载