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 理解题目 很显然,通过管理关系的不断连边,最后连出来的肯定是一棵树,那么不难得出,当一个忍者 ...
随机推荐
- Maven依赖范围及传递
.Maven因为执行一系列编译.测试和部署运行等操作,在不同的操作下使用的classpath不同,依赖范围就是用来控制依赖与三种 classpath(编译classpath.测试classpath.运 ...
- C#/.Net判断是否为周末/节假日
判断节假日请求的Api:http://tool.bitefu.net/jiari/ /// <summary> /// 判断是不是周末/节假日 /// </summary> / ...
- atlassian、jira账户无法注册来这里
进入https://www.atlassian.com/try 注册成功 登陆 再次到邮箱点击链接 登陆成功(已经处于登陆状态:此时你已经拥有一个atlassian账户了)
- Jquery实现检测用户输入用户名和密码不能为空
要求 1.用户名和密码为空点击登录时提示相应的提示 2.获取用户名输入框时,错误提示清除 思路 1.创建1个input-text标签和1个input-password标签,1个input-botton ...
- Qt QTimer
QTimer类提供了重复和单次触发信号的定时器. QTimer类为定时器提供了一个高级别的编程接口.很容易使用:首先,创建一个QTimer,连接timeout()信号到适当的槽函数,并调用start( ...
- pycharm pip 源修改以及包管理(转载)
转载自(https://www.u3v3.com/ar/1352) pycharm下如何将默认的pip源改成国内能快速访问的源, 以及如何进行包管理 pycharm 是一款进行python项目开发的利 ...
- 洛谷P1550打井
打井 题目 该题是一个最小生成树的好题,但是比起一般的最小生成树来说他不仅仅有各个井相连,而且还要和地下水相连,所以地下水我们也可以看成一口井. 代码 #include <bits/stdc++ ...
- synchronized 关键字解析
synchronized 关键字解析 同步锁依赖于对象,每个对象都有一个同步锁. 现有一成员变量 Test,当线程 A 调用 Test 的 synchronized 方法,线程 A 获得 Test 的 ...
- 解决Eclipse每次修改完代码后需要先Clean,不然修改的代码无效
工具栏 Project-->Build Automatically 勾选上即可
- BSGS及扩展BSGS总结(BSGS,map)
蒟蒻哪里有什么总结,只能点击%YL% 还有这位ZigZagK大佬的blog \(\mbox{BSGS}\) 模板题:洛谷P3846 [TJOI2007]可爱的质数 给定\(a,b\)和模数\(\mbo ...