Luogu P1552 [APIO2012]派遣 主席树
题目链接 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]派遣 主席树的更多相关文章
- [luogu P1552] [APIO2012]派遣
[luogu P1552] [APIO2012]派遣 题目背景 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿. 题目描述 在这个帮派里,有一名忍者被称之为Master.除 ...
- Luogu P1552 [APIO2012]派遣【左偏树】By cellur925
题目传送门 $Chat$ 哈哈哈我xj用dfs序乱搞竟然炸出了66分....(其实还是数据水,逃) $Sol$ 首先我们应该知道,一个人他自己的满意度与他子树所有节点的领导力是无关的,一个人的满意度受 ...
- luogu P1552 [APIO2012]派遣 题解--可并堆/贪心
题目链接: https://www.luogu.org/problemnew/show/P1552 分析: 一开始愣是没看懂题,后面发现就是你要找一个树上点集使得各点权值之和小于\(M\),并且找一个 ...
- BZOJ2809&&LG1552 APIO2012派遣(线段树合并)
BZOJ2809&&LG1552 APIO2012派遣(线段树合并) 题面 自己找去 HINT 简化一题面就是让你从每个点的子树中以\(<=m\)的代价选取尽可能多的点,然后乘上 ...
- [Apio2012]dispatching 主席树做法
bzoj 2809: [Apio2012]dispatching http://www.lydsy.com/JudgeOnline/problem.php?id=2809 Description 在一 ...
- BZOJ 2809: [Apio2012]dispatching [主席树 DFS序]
传送门 题意:查询树上根节点值*子树中权值和$\le m$的最大数量 最大值是多少 求$DFS$序,然后变成区间中和$\le m$最多有几个元素,建主席树,然后权值线段树上二分就行了 $WA$:又把边 ...
- 洛谷P1552 [APIO2012] 派遣 [左偏树,树形DP]
题目传送门 忍者 Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都 ...
- 洛谷P1552 [APIO2012]派遣(左偏树)
传送门 做这题的时候现学了一波左偏树2333(好吧其实是当初打完板子就给忘了) 不难发现肯定是选子树里权值最小的点且选得越多越好 但如果在每一个点维护一个小根堆,我们得一直找知道权值大于m为止,时间会 ...
- [洛谷P1552] [APIO2012]派遣(左偏树)
这道题是我做的左偏树的入门题,奈何还是看了zsy大佬的题解才能过,唉,我太弱了. 左偏树总结 Part 1 理解题目 很显然,通过管理关系的不断连边,最后连出来的肯定是一棵树,那么不难得出,当一个忍者 ...
随机推荐
- How to install rime on Debian
apt-get install ibus ibus-rime librime-data-wubi reboot cp ~/.config/ibus/rime/default.yaml ~/.confi ...
- BZOJ 1443 游戏(二分图博弈)
新知识get. 一类博弈问题,基于以下条件: 1.博弈者人数为两人,双方轮流进行决策.2.博弈状态(对应点)可分为两类(状态空间可分为两个集合),对应二分图两边(X集和Y集).任意合法的决策(对应边) ...
- JSON 解析 (三)—— FastJSON与Jackson比较
一.方便性与性能 调用方便性而言: FastJSON提供了大量静态方法,调用简洁方便 Jackson须实例化类,调用相对繁琐,可通过封装成JSON工具类简化调用 性能而言: FastJSON反序列化的 ...
- Python Argparse模块
argparse模块 在Python中,argparse模块是标准库中用来解析命令行参数的模块,用来替代已经过时的optparse模块.argparse模块能够根据程序中的定义从sys.argv中解析 ...
- Python中的numpy模块解析
numpy 1. 创建对象 维度(dimensions):轴 轴的个数:秩(rank) Numpy最重要的一个特点就是其N维数组对象(即ndarray) 创建数组最简单的函数就是用array函数: ...
- 使用IDEA部署项目到远程服务器
1.选择Tools -> Deployment -> Configuration... 2.配置连接信息,Linux服务器一般都选择SFTP 3.配置本地上传文件路径.远程上传文件路径 4 ...
- MySQL免安装版,遇到MSVCR120.dll文件丢失错误的解决方案
下载 VC redist packages for x64,下载完成,点击运行即可.
- MT【272】更大的视野,更好的思路.
已知$f(x)=\sum\limits_{k=1}^{2017}\dfrac{\cos kx}{\cos^k x},$则$f(\dfrac{\pi}{2018})=$_____ 分析:设$g(x)=\ ...
- 【模板】可持久化文艺平衡树-可持久化treap
题目链接 题意 对于各个以往的历史版本实现以下操作: 在第 p 个数后插入数 x . 删除第 p 个数. 翻转区间 [l,r],例如原序列是 \(\{5,4,3,2,1\}\),翻转区间 [2,4] ...
- linux中shell脚本引用另一shell脚本
调用有三种方法: 1.fork:不同的shell,调用后返回父shell,子shell从父shell中继承变量,但子shell的变量不会带回父shell,直接用path/to/file.sh调用: 2 ...