博客
关于我
【ybt金牌导航4-1-1】【luogu P1552】派遣(左偏树模板)
阅读量:322 次
发布时间:2019-03-04

本文共 2266 字,大约阅读时间需要 7 分钟。

这道题目要求我们在一棵有根树的子树中选择一些点,使得它们的花费总和不超过给定的值,并且它们的个数乘以贡献值尽可能大。我们可以通过贪心算法和左偏树的数据结构来高效解决这个问题。

思路解析

  • 贪心策略

    • 我们需要选择一个点,并在它的子树中选一些点,使得花费总和不超过给定的值。
    • 每个点的贡献相同,因此我们可以选择花费最小的点以使得个数乘以贡献的值最大化。
  • 左偏树

    • 左偏树是一种优先队列,支持快速的插入、删除和合并操作。
    • 左偏树具有两个重要性质:
      • 大根堆的性质:堆顶的键值大于其左右子树。
      • 距离定义:每个节点到最近的外节点的距离最小,且左子树的距离不小于右子树的距离。
  • 堆的合并与删除

    • 合并操作:将两个堆合并成一个新的堆,确保新的堆满足左偏树的性质。
    • 删除操作:删除堆顶节点后,合并其左右子树,并调整堆的性质。
  • 构建与优化

    • 单点插入:将单点视为左偏树,通过合并操作构建树。
    • 大规模构建:使用队列逐步合并单点堆,得到最终的优化树。
    • 删除已知节点:通过调整树结构,确保删除后的堆依然满足性质。
  • 代码实现

    #include 
    #include
    using namespace std;#define ll long longstruct road { ll to, nxt;} e[300001];struct node { ll l, r, key, dis, num, sum;} tree[2000001];ll n, m, tot, y, rt[100001];ll c[100001], l[100001];ll le[100001], fa[100001];ll ans;void add(ll x, ll y) { e[++KK] = { y, le[x] }; le[x] = KK;}ll make_tree(ll x) { tree[++tot] = { 0, 0, c[x], -1, 1, c[x] }; return tot;}ll merge(ll x, ll y) { if (!x) return y; if (!y) return x; if (tree[x].key < tree[y].key) { swap(x, y); } tree[x].r = merge(tree[x].r, y); if (tree[tree[x].l].dis < tree[tree[x].r].dis) { swap(tree[x].l, tree[x].r); } tree[x].dis = tree[tree[x].r].dis + 1; tree[x].num = tree[tree[x].l].num + tree[tree[x].r].num + 1; tree[x].sum = tree[tree[x].l].sum + tree[tree[x].r].sum + tree[x].key; return x;}void insert(ll x, ll Y) { ll X = make_tree(x); Y = merge(X, Y);}ll delete_max(ll x) { return merge(tree[x].l, tree[x].r);}void dfs(ll now, ll father) { fa[now] = father; for (ll i = le[now]; i; i = e[i].nxt) { if (e[i].to != father) { dfs(e[i].to, now); rt[now] = merge(rt[now], rt[e[i].to]); while (tree[rt[now]].sum > m) { rt[now] = delete_max(rt[now]); } ans = max(ans, l[now] * tree[rt[now]].num); } }}int main() { scanf("%lld %lld", &n, &m); for (ll i = 1; i <= n; ++i) { scanf("%lld %lld %lld", &y, &c[i], &l[i]); add(y, i); } for (ll i = 1; i <= n; ++i) { rt[i] = make_tree(i); if (tree[i].sum > m) { rt[i] = delete_max(rt[i]); } } dfs(1, 0); printf("%lld", ans); return 0;}

    总结

    通过贪心算法和左偏树的数据结构,我们可以高效地解决这道题。贪心策略确保我们每次选择花费最小的点,从而最大化个数乘以贡献的值。左偏树的合并与删除操作优化了数据结构的性能,使得算法在大规模数据下依然高效。

    转载地址:http://vovh.baihongyu.com/

    你可能感兴趣的文章
    Objective-C实现check strong password检查密码强度算法(附完整源码)
    查看>>
    Objective-C实现circle sort圆形排序算法(附完整源码)
    查看>>
    Objective-C实现coulombs law库仑定律算法(附完整源码)
    查看>>
    Objective-C实现DBSCAN聚类算法(附完整源码)
    查看>>
    Objective-C实现dijkstra银行家算法(附完整源码)
    查看>>
    Objective-C实现Dinic算法(附完整源码)
    查看>>
    Objective-C实现disjoint set不相交集算法(附完整源码)
    查看>>
    Objective-C实现DisjointSet并查集的算法(附完整源码)
    查看>>
    Objective-C实现djb2哈希算法(附完整源码)
    查看>>
    Objective-C实现DNF排序算法(附完整源码)
    查看>>
    Objective-C实现double factorial iterative双阶乘迭代算法(附完整源码)
    查看>>
    Objective-C实现double factorial recursive双阶乘递归算法(附完整源码)
    查看>>
    Objective-C实现double hash双哈希算法(附完整源码)
    查看>>
    Objective-C实现double linear search recursion双线性搜索递归算法(附完整源码)
    查看>>
    Objective-C实现DoublyLinkedList双链表的算法(附完整源码)
    查看>>
    Objective-C实现DPLL(davisb putnamb logemannb loveland)算法(附完整源码)
    查看>>
    Objective-C实现Edmonds-Karp算法(附完整源码)
    查看>>
    Objective-C实现EEMD算法(附完整源码)
    查看>>
    Objective-C实现EM算法(附完整源码)
    查看>>
    Objective-C实现EM算法(附完整源码)
    查看>>