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


    【题目链接】 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[N];
    LL ans,sum[N],size[N];
    int C[N],L[N],root[N];
    struct SHeap{
        int v[N],l[N],r[N];
        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
    ",ans);
        return 0;
    }
  • 相关阅读:
    python 学习笔记(四)(流程控制)
    python 写斐波那契数列
    python 部分术语对照表
    python 学习笔记(三)(对前两节的补充)
    python # -*- coding: utf-8 -*-
    写出更好的 JavaScript 条件语句
    PHP消息队列实现及应用
    VUE3.0 路由去掉#号
    php设计模式
    workerman 可能需要用到的函数
  • 原文地址:https://www.cnblogs.com/forever97/p/bzoj2809.html
Copyright © 2020-2023  润新知