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; }