题目链接 Click Here

这个题好像大多数人用的都是左偏树啊?这里我来贡献一发主席树的解法。

把题目中的问题抽象出来,其实就是询问每一个点的子树中,工资前\(tot_i\)大的点,使它们的和满足\(\sum cost_i<=m\),在此前提下使\(tot_i\)尽可能大,答案就是\(ans=max(tot_i*lead_i)\)。

如果只有一个点的话直接二分一下就好了,但现在树上的每一个点都可能是答案的产生1处。为了便于访问每一棵子树,我们把原先的树按\(dfs\)序划分,子树显然就是连续的一个序列。紧接着我们按\(dfs\)序对整棵树进行维护,最后在主席树上每个点二分一下\(tot_i\)的大小就好啦~

#include <bits/stdc++.h>
using namespace std; #define int long long const int N = 100010;
int ans;
int n, m, rt, cnt, sz[N], dfn[N], cost[N], lead[N], head[N]; struct edge {
int nxt, to; edge (int _nxt = 0, int _to = 0) {
nxt = _nxt, to = _to;
}
}e[N << 1]; void add_len (int u, int v) {
e[++cnt] = edge (head[u], v); head[u] = cnt;
e[++cnt] = edge (head[v], u); head[v] = cnt;
} #define mid ((l + r) >> 1) int tot; struct Segment_Tree {
struct Segment_Node {
int ls, rs, sz, sum;
Segment_Node () {sum = ls = rs = sz = 0;}
}t[N << 5]; int modify (int _rt, int l, int r, int w) {
int p = ++tot;
t[p].ls = t[_rt].ls;
t[p].rs = t[_rt].rs;
t[p].sz = t[_rt].sz + 1;
t[p].sum = t[_rt].sum + w;
if (l != r) {
if (w <= mid) {
t[p].ls = modify (t[_rt].ls, l, mid, w);
} else {
t[p].rs = modify (t[_rt].rs, mid + 1, r, w);
}
}
return p;
} #undef mid int query (int u, int v, int l, int r, int m) {
int ans = 0;
while (l < r) {
int mid = (l + r) >> 1;
int suml = t[t[v].ls].sum - t[t[u].ls].sum;
// printf ("v = %d, t[v].sum = %d, t[v].sz = %d, t[ls].sum = %d, t[ls].sz = %d\n", v, t[v].sum, t[v].sz, t[t[v].ls].sum, t[t[v].ls].sz);
// printf ("l = %d, r = %d, m = %d, mid = %d, suml = %d, sz = %d\n", l, r, m, mid, suml, t[t[v].ls].sz - t[t[u].ls].sz);
if (m <= suml) {
u = t[u].ls;
v = t[v].ls;
r = mid;
} else {
ans += t[t[v].ls].sz - t[t[u].ls].sz;
u = t[u].rs;
v = t[v].rs;
l = mid + 1;
m -= suml;
}
}
// printf ("m = %d, r = %d, ans = %d\n", m, r, ans);
ans += floor ((1.0 * m) / (1.0 * r));
// printf ("ans = %d\n", ans);
return ans;
}
}tree; int root[N];
void pre (int u, int fa) {
sz[u] = 1;
dfn[u] = ++dfn[0];
root[dfn[u]] = tree.modify (root[dfn[u] - 1], 1, m, cost[u]);
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (v != fa) {
pre (v, u);
sz[u] += sz[v];
}
}
} signed main () {
cin >> n >> m;
for (int u = 1; u <= n; ++u) {
static int v;
cin >> v >> cost[u] >> lead[u];
if (v == 0) {
rt = u;
} else {
add_len (u, v);
}
}
pre (rt, 0);
for (int u = 1; u <= n; ++u) {
int dfnu = dfn[u];
int dfnv = dfn[u] + sz[u] - 1;
ans = max (ans, 1LL * lead[u] * tree.query (root[dfnu - 1], root[dfnv], 1, m, m));
}
cout << ans << endl;
}

Luogu P1552 [APIO2012]派遣 主席树的更多相关文章

  1. [luogu P1552] [APIO2012]派遣

    [luogu P1552] [APIO2012]派遣 题目背景 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿. 题目描述 在这个帮派里,有一名忍者被称之为Master.除 ...

  2. Luogu P1552 [APIO2012]派遣【左偏树】By cellur925

    题目传送门 $Chat$ 哈哈哈我xj用dfs序乱搞竟然炸出了66分....(其实还是数据水,逃) $Sol$ 首先我们应该知道,一个人他自己的满意度与他子树所有节点的领导力是无关的,一个人的满意度受 ...

  3. luogu P1552 [APIO2012]派遣 题解--可并堆/贪心

    题目链接: https://www.luogu.org/problemnew/show/P1552 分析: 一开始愣是没看懂题,后面发现就是你要找一个树上点集使得各点权值之和小于\(M\),并且找一个 ...

  4. BZOJ2809&&LG1552 APIO2012派遣(线段树合并)

    BZOJ2809&&LG1552 APIO2012派遣(线段树合并) 题面 自己找去 HINT 简化一题面就是让你从每个点的子树中以\(<=m\)的代价选取尽可能多的点,然后乘上 ...

  5. [Apio2012]dispatching 主席树做法

    bzoj 2809: [Apio2012]dispatching http://www.lydsy.com/JudgeOnline/problem.php?id=2809 Description 在一 ...

  6. BZOJ 2809: [Apio2012]dispatching [主席树 DFS序]

    传送门 题意:查询树上根节点值*子树中权值和$\le m$的最大数量 最大值是多少 求$DFS$序,然后变成区间中和$\le m$最多有几个元素,建主席树,然后权值线段树上二分就行了 $WA$:又把边 ...

  7. 洛谷P1552 [APIO2012] 派遣 [左偏树,树形DP]

    题目传送门 忍者 Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都 ...

  8. 洛谷P1552 [APIO2012]派遣(左偏树)

    传送门 做这题的时候现学了一波左偏树2333(好吧其实是当初打完板子就给忘了) 不难发现肯定是选子树里权值最小的点且选得越多越好 但如果在每一个点维护一个小根堆,我们得一直找知道权值大于m为止,时间会 ...

  9. [洛谷P1552] [APIO2012]派遣(左偏树)

    这道题是我做的左偏树的入门题,奈何还是看了zsy大佬的题解才能过,唉,我太弱了. 左偏树总结 Part 1 理解题目 很显然,通过管理关系的不断连边,最后连出来的肯定是一棵树,那么不难得出,当一个忍者 ...

随机推荐

  1. How to reset macOS Icon Cache

    find . -name cuthead.txt find /private/var/folders/ -name 'com.apple.dock.iconcache' -delete find /p ...

  2. linux硬件数据

    Linux 文件详解 lrwxrwxrwx root root 8月 bin -> usr/bin //二进制目录 存放了许多GNU用户极工具 dr-xr-xr-x. root root 8月 ...

  3. 微信小程序 canvas 字体自动换行(支持换行符)

    微信小程序 canvas 自动适配 自动换行,保存图片分享到朋友圈  https://github.com/richard1015/News 微信IDE演示代码https://developers.w ...

  4. [BZOJ 3498] [PA 2009] Cakes

    Description \(n\) 个点 \(m\) 条边,每个点有一个点权 \(a_i\). 对于任意一个三元环 \((i,j,k)(i<j<k)\),它的贡献为 \(\max(a_i, ...

  5. VM虚拟机截图方法介绍

    可以先安装QQ之类的截图软件,但比较麻烦,而且截图之后还需要安装VMware Tools等工具才能拿到物理机上 先定向到物理机,快捷键为CTRL+ALT,之后在用qq截图快捷键ctrl+alt+a即可 ...

  6. 第二十天 模块 sys os os下path settings random shuit

    一.sys模块 1.sys.argv 命令行参数List,第一个元素是程序本身路径 2.sys.exit(n) 退出程序,正常退出时exit(0) 3.sys.version 获取Pythonn解释程 ...

  7. HDU5977 Garden of Eden 【FMT】【树形DP】

    题目大意:求有所有颜色的路径数. 题目分析:参考codeforces997C,先利用基的FMT的性质在$O(2^k)$做FMT,再利用只还原一位的特点在$O(2^k)$还原,不知道为什么网上都要点分治 ...

  8. BZOJ 4326 运输计划

    二分答案+树链剖分+树上差分 我们假设x是最小的花费,可以想到给定x,所有运输计划中花费大于x的计划必须经过虫洞,且最长的一条的花费减去虫洞所在边的花费要小于等于x 那么对于x,虫洞所在的位置肯定是确 ...

  9. ☆ [HDU2089] 不要62「数位DP」

    类型:数位DP 传送门:>Here< 题意:问区间$[n,m]$的数字中,不含4以及62的数字总数 解题思路 数位DP入门题 先考虑一般的暴力做法,整个区间扫一遍,判断每个数是否合法并累计 ...

  10. python+selenium+unnitest写一个完整的登陆的验证

    import unittest from selenium import webdriver from time import sleep class lonInTest (unittest.Test ...