• [洛谷P1552][APIO2012]派遣


    题目大意:有一棵$n$个点的树,和一个费用$m$,每个点有一个费用和价值,请选一个点,再从它的子树中选取若干个点,使得那个点的价值乘上选的点的个数最大,要求选的点费用总和小于等于$m$

    题解:树形$dp$,贪心可得选的点一定是费用最少的几个点,可以用可并堆,大根堆,若总费用大于$m$就把堆顶弹掉,直到小于等于$m$,更新答案

    卡点:

    C++ Code:

    #include <algorithm>
    #include <cstdio>
    #define maxn 100010
    int head[maxn], cnt;
    struct Edge {
    	int to, nxt;
    } e[maxn];
    inline void addedge(int a, int b) {
    	e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
    }
    
    long long ans;
    int V[maxn], lc[maxn], rc[maxn], dis[maxn];
    int sum[maxn], sz[maxn];
    
    inline int update(int x) {
    	sz[x] = sz[lc[x]] + sz[rc[x]] + 1;
    	sum[x] = sum[lc[x]] + sum[rc[x]] + V[x];
    	return x;
    }
    int merge(int x, int y) {
    	if (!x || !y) return x | y;
    	if (V[x] < V[y]) std::swap(x, y);
    	rc[x] = merge(rc[x], y);
    	if (dis[rc[x]] > dis[lc[x]]) std::swap(lc[x], rc[x]);
    	dis[x] = dis[rc[x]] + 1;
    	return update(x);
    }
    inline int pop(int x) {return merge(lc[x], rc[x]);}
    
    int root, n, m;
    int L[maxn];
    int dfs(int u, int fa = 0) {
    	int rt = u;
    	for (int i = head[u]; i; i = e[i].nxt) {
    		int v = e[i].to, __rt = dfs(v);
    		rt = merge(rt, __rt);
    		while (sum[rt] > m) rt = pop(rt);
    	}
    	ans = std::max(ans, static_cast<long long> (sz[rt]) * L[u]); 
    	return rt;
    }
    int main() {
    	scanf("%d%d", &n, &m); dis[0] = -1;
    	for (int i = 1, x; i <= n; i++) {
    		scanf("%d%d%d", &x, V + i, L + i);
    		sum[i] = V[i], sz[i] = 1;
    		if (x) addedge(x, i);
    		else root = i;
    	}
    	dfs(root);
    	printf("%lld
    ", ans);
    	return 0;
    }
    

      

  • 相关阅读:
    Spring实现声明式事务
    Spring整合MyBatis
    Spring AOP
    代理模式
    Bean的作用域
    Spring的配置
    HQL题目记录以及解题思路--持续更新
    数仓学习之路一:数仓理论
    DBeaver连接Hive遇到的坑
    MySQL常见面试题
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/10028302.html
Copyright © 2020-2023  润新知