可并堆-bzoj2809: [Apio2012]dispatching

http://www.lydsy.com/JudgeOnline/problem.php?id=2809
本来1A的,结果,ll没开全;
首先题目看懂,这个题目不长,但是要看懂;
看懂之后就会发现整个结构是树型的;
然后我们就可以搞事了呀;
和树形dp很像的;
我们维护n个大根堆;
不断把子节点合并到跟节点;
合并完了就不断弹出堆顶,就是工资最大的数;
直到当前堆里面全部工资小于等于m;
更新答案;
注意的是这里的一个堆,里面的参数的指向不清晰;
模版题目的指向是很清晰的;
这个就要严谨的逻辑关系;

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define Ll long long
using namespace std;
struct cs{
    int to,next;
}a[100000];
struct heap{
    Ll xx,yy,vv,money,num,fa;//vv是领导值,num堆内是有几个点,sum是总工资 
    Ll sum;
}q[100001];
int head[100001];
Ll n,m,x,y,z,ll,S;
Ll ans;
void init(int x,int y){
    a[++ll].to=y;
    a[ll].next=head[x];
    head[x]=ll;
}
int merge(int x,int y){
    if(!x)return y;
    if(!y)return x;
    if(q[x].money<q[y].money)swap(x,y);
    q[x].yy=merge(q[x].yy,y);
    swap(q[x].xx,q[x].yy);
    return x;
}
void del(int x){//弹出堆顶 
    int xx=q[x].fa;
    q[x].num--;
    q[x].sum-=q[xx].money;
    q[x].fa=merge(q[xx].xx,q[xx].yy);
}
void dfs(int x){
    for(int k=head[x];k;k=a[k].next){
        dfs(a[k].to);
        q[x].num+=q[a[k].to].num;
        q[x].sum+=q[a[k].to].sum;
        q[x].fa=merge(q[x].fa,q[a[k].to].fa);
    }
    while(q[x].sum>m)del(x);
    ans=max(ans,q[x].vv*q[x].num);
}
int main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld%lld%lld",&x,&y,&z);
        q[i].money=y;
        q[i].sum=y;
        q[i].num=1;
        q[i].vv=z;
        q[i].fa=i;
        init(x,i);
        if(!x)S=i;
    }
    dfs(S);
    printf("%lld",ans);
}
posted @ 2017-03-02 11:16  largecube233  阅读(110)  评论(0编辑  收藏  举报