您的位置:首页 > 其它

BZOJ 2809 [Apio2012]dispatching(斜堆+树形DP)

2017-07-12 14:19 274 查看
【题目链接】 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
;
LL ans,sum
,size
;
int C
,L
,root
;
struct SHeap{
int v
,l
,r
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: