bzoj2809 可并堆(左偏树)

HYSBZ - 2809

题意:给你一颗树,每个节点有2个权值,li表示该点的领导力,ci表示花费,选择一个子树,该子树的根作为领导,然后从这个子树下选出x个节点,所有选出的节点的花费和不大于m,得到一个价值为 领导力乘选出的节点数, 即ans=li*x,求最大值

思路:首先可以知道的是当选出了一个子树时,只要贪心得在这颗子树下每次取出花费最小的即可,直到总花费大于m,即可以dfs每次选出一个子树,先将所有点选取,然后每次删除花费最大的节点,直到总花费不大于m,用可并堆维护即可

AC代码:

#include "iostream"
#include "iomanip"
#include "string.h"
#include "stack"
#include "queue"
#include "string"
#include "vector"
#include "set"
#include "map"
#include "algorithm"
#include "stdio.h"
#include "math.h"
#pragma comment(linker, "/STACK:102400000,102400000")
#define bug(x) cout<<x<<" "<<"UUUUU"<<endl;
#define mem(a,x) memset(a,x,sizeof(a))
#define step(x) fixed<< setprecision(x)<<
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define ll long long
#define endl ("\n")
#define ft first
#define sd second
#define lrt (rt<<1)
#define rrt (rt<<1|1)
using namespace std;
const ll mod=1e9+7;
const ll INF = 1e18+1LL;
const int inf = 1e9+1e8;
const double PI=acos(-1.0);
const int N=1e5+100;

int rt[N], ls[N], rs[N], d[N], siz[N], val[N], cnt = 0;
int head[N], to[N], nex[N], li[N], tot;
int n, M;
ll ans, sum[N];
void add(int u, int v) {
    to[tot] = v;
    nex[tot] = head[u];
    head[u] = tot++;
}

void updata(int x) {
    siz[x] = siz[ls[x]]+siz[rs[x]]+1;
    sum[x] = sum[ls[x]]+sum[rs[x]]+val[x];
    if(d[ls[x]] < d[rs[x]]) swap(ls[x], rs[x]);
    if(!rs[x]) d[x] = 0;
    else d[x] = d[rs[x]] + 1;
}

int Merge(int x, int y) {
    if(!x || !y) return x+y;
    if(val[x] < val[y]) swap(x, y);
    rs[x] = Merge(y, rs[x]);
    updata(x);
    return x;
}

void pop(int &x) {
    int last = x;
    x = Merge(ls[x], rs[x]);
    ls[last] = rs[last] = d[last] = 0;
}

void dfs(int u) {
    rt[u] = u, siz[u] = 1, sum[u] = val[u];
    for(int i=head[u]; i!=-1; i=nex[i]) {
        int v = to[i];
        dfs(v);
        rt[u] = Merge(rt[u], rt[v]);
    }
    while(siz[rt[u]] && sum[rt[u]] > M) pop(rt[u]);
    ans = max(ans, (ll)siz[rt[u]]*(ll)li[u]);
}

int main(){
    scanf("%d %d", &n, &M);
    mem(head, -1);
    int root = 0;
    for(int i=1; i<=n; ++i) {
        int b, c, l;
        scanf("%d %d %d", &b, &c, &l);
        val[i] = c, li[i] = l;
        add(b, i);
        if(b == 0) root = i;
    }
    dfs(root);
    printf("%lld\n", ans);
    return 0;
}

 

posted on 2018-04-16 23:08  lazzzy  阅读(121)  评论(0编辑  收藏  举报

导航