BZOJ2809 dispatching

题目大意

  给你一棵有根树,每个节点内有两个值:领导力和费用。现要求选择一个子树,并在子树内选择若干个节点,使得选择的节点的费用总和不超出预算,且子树的根的领导力乘以选择的节点的数量的值最大。

思路

  由贪心思想,处理每个子树时,我们优先保留费用低的节点,当节点的总费用超出预算时,我们优先去除费用最高的节点。贪心的优越正确性显然。要达到这一点,我们很容易想到用大根堆来维护。问题在于,怎么生成这个堆呢?可以看到一个子树的堆可以由它的各个子树的堆合并而成。所以我们的堆用可并堆。按照Dfs后序遍历处理各个子树即可。

注意事项

  • 堆合并后,要更新堆的根。
  • 注意运算时要开long long。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

const int MAX_NODE = 100010;

template<class KeyType>

struct Heap
{
private:
    struct Node
    {
        Node *Father, *LeftSon, *RightSon;
        int Dist, Size;
        KeyType Key, Sum;
        
        Node(int key) : Father(NULL), LeftSon(NULL), RightSon(NULL), Key(key), Sum(key), Dist(0), Size(1) {}
        
        void Refresh()
        {
            Dist = RightSon ? RightSon->Dist + 1 : 0;
            Sum = Key;
            Size = 1;
            if (LeftSon)
            {
                Sum = Sum + LeftSon->Sum;
                Size += LeftSon->Size;
            }
            if (RightSon)
            {
                Sum = Sum + RightSon->Sum;
                Size += RightSon->Size;
            }
        }
    }*Root;
    
    Node *Merge(Node *a, Node *b)
    {
        if(!a)
            return b;
        if (!b)
            return a;
        if(a->Key < b->Key)
            swap(a, b);
        a->RightSon = Merge(a->RightSon, b);
        if(a->RightSon)
            a->RightSon->Father = a;
        if((a->LeftSon ? a->LeftSon->Dist : 0) < (a->RightSon ? a->RightSon->Dist : 0))
            swap(a->LeftSon, a->RightSon);
        a->Refresh();
        return a;
    }
    
public:
    Heap() :Root(NULL){}
    
    void Intake(Heap *a)
    {
        Root = Merge(Root, a->Root);
    }
    
    void Push(KeyType key)
    {
        Root = Merge(Root, new Node(key));
    }
    
    void Pop()
    {
        Root = Merge(Root->LeftSon, Root->RightSon);
    }
    
    KeyType Sum()
    {
        if(!Root)
            return 0;
        return Root->Sum;
    }
    
    int Size()
    {
        if (!Root)
            return 0;
        return Root->Size;
    }
};

struct Graph
{
private:
    int M;
    long long Ans;
    
    struct Node
    {
        vector<Node*> Sons;
        int Cost, Val;
        
        Node(){}
        
        Node(int cost, int val) : Cost(cost), Val(val) {}
    }_nodes[MAX_NODE], *Root;
    int _vCount;
    
    Heap<long long> *Dfs(Node *cur)
    {
        Heap<long long> *curHeap = new Heap<long long>();
        if (cur == NULL)
            return curHeap;
        for (int i = 0; i < cur->Sons.size(); i++)
            curHeap->Intake(Dfs(cur->Sons[i]));
        curHeap->Push(cur->Cost);
        while (curHeap->Sum() > M)
            curHeap->Pop();
        Ans = max(Ans, (long long)cur->Val * (long long)curHeap->Size());
        return curHeap;
    }
    
public:
    void Init(int n, int m)
    {
        _vCount = n;
        M = m;
        Ans = 0;
    }
    
    void SetNode(int cur, int fa, int cost, int val)
    {
        if(fa != 0)
            _nodes[fa].Sons.push_back(_nodes + cur);
        else
            Root = _nodes + cur;
        _nodes[cur].Cost = cost;
        _nodes[cur].Val = val;
    }
    
    long long GetAns()
    {
        Dfs(Root);
        return Ans;
    }
}g;

int main()
{
    int totNode, m, fa, cost, val;
    scanf("%d%d", &totNode, &m);
    g.Init(totNode, m);
    for (int i = 1; i <= totNode; i++)
    {
        scanf("%d%d%d", &fa, &cost, &val);
        g.SetNode(i, fa, cost, val);
    }
    printf("%lld\n", g.GetAns());
    return 0;
}
View Code

 

posted @ 2018-07-24 16:14  headboy2002  阅读(113)  评论(0编辑  收藏  举报