P1552 [APIO2012]派遣
链接
https://www.luogu.org/problemnew/show/P1552
思路
忍者数量肯定越多越好
那就从下到上的合并它的孩子
左偏树的话
顺便维护一个tot,大头堆,如果tot大于了m,把大的删掉
如果左偏树忘干净了或者没学的话
线段树合并也是个不错的选择
直接权值线段树合并就好,内存30倍会炸,也许是我没离散化的缘故吧
查询在线段树上面二分
左偏树代码
#include <bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
#define ll long long
using namespace std;
const int maxn=100047;
inline int read() {
int x=0,f=1;char s=getchar();
for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
return x*f;
}
struct edge {
int v,nxt;
}e[maxn];
int head[maxn],tot;
void add_edge(int u,int v) {
e[++tot].v=v;e[tot].nxt=head[u];head[u]=tot;
}
int n,m,mone;
ll sum[maxn],ans;
int size[maxn];
int ch[maxn][2],dis[maxn],val[maxn],xs[maxn];
int work(int a,int b) {
if(!a||!b) return a+b;
if(val[a]<val[b]) swap(a,b);
ch[a][1]=work(ch[a][1],b);
if(dis[ch[a][0]]<dis[ch[a][1]]) swap(ch[a][0],ch[a][1]);
dis[a]=dis[ch[a][1]]+1;
return a;
}
int merge(int x,int y) {
int tmp=work(x,y);
y=x^y^tmp,x=tmp;
sum[x]+=sum[y];
size[x]+=size[y];
return tmp;
}
int delet(int x) {
int tmp=work(ch[x][0],ch[x][1]);
size[tmp]=size[x]-1;
sum[tmp]=sum[x]-val[x];
return tmp;
}
int dfs(int u) {
int rt=u;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
int tmp=dfs(v);
rt=merge(rt,tmp);
}
while(sum[rt]>mone) rt=delet(rt);
ans=max(ans,xs[u]*(ll)size[rt]);
return rt;
}
int main() {
n=read(),mone=read();
int root;
FOR(i,1,n) {
int x=read();
val[i]=read();xs[i]=read();
sum[i]=val[i];size[i]=1;
if(x) add_edge(x,i);
else root=i;
}
int wuyong=dfs(root);
cout<<ans<<"\n";
return 0;
}
线段树合并代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <utility>
#define ll long long
using namespace std;
const int N=1e5+7;
int read() {
int x=0,f=1;char s=getchar();
for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
return x*f;
}
int n,m,money[N],leader[N],rt[N];
vector<int> G[N];
struct node {
int l,r,siz;
ll tot;
}e[N*30];
void pushup(int rt) {
e[rt].siz=e[e[rt].l].siz+e[e[rt].r].siz;
e[rt].tot=e[e[rt].l].tot+e[e[rt].r].tot;
}
int cnt;
void insert(int l,int r,int L,int &rt) {
rt=++cnt;
if(l==r) {
e[rt].siz++;
e[rt].tot+=l;
return;
}
int mid=(l+r)>>1;
if(L<=mid) insert(l,mid,L,e[rt].l);
else insert(mid+1,r,L,e[rt].r);
pushup(rt);
}
int merge(int l,int r,int x,int y) {
if(!x||!y) return x+y;
if(l==r) {
e[x].siz+=e[y].siz;
e[x].tot+=e[y].tot;
return x;
}
int mid=(l+r)>>1;
e[x].l=merge(l,mid,e[x].l,e[y].l);
e[x].r=merge(mid+1,r,e[x].r,e[y].r);
pushup(x);
return x;
}
int query(int l,int r,int k,int rt) {
if(l==r) return k>=e[rt].tot ? e[rt].siz : 0;
int mid=(l+r)>>1;
if(e[e[rt].l].tot>=k) return query(l,mid,k,e[rt].l);
else return e[e[rt].l].siz+query(mid+1,r,k-e[e[rt].l].tot,e[rt].r);
}
ll ans;
void dfs(int u) {
insert(1,1000000000,money[u],rt[u]);
for(vector<int>::iterator it=G[u].begin();it!=G[u].end();++it) {
dfs(*it);
rt[u]=merge(1,1000000000,rt[u],rt[*it]);
}
ans=max(ans,(ll)leader[u]*query(1,1000000000,m,rt[u]));
}
int main() {
n=read(),m=read();
for(int i=1;i<=n;++i) {
int x=read();
money[i]=read();
leader[i]=read();
G[x].push_back(i);
}
dfs(1);
printf("%lld",ans);
return 0;
}
P1552 [APIO2012]派遣的更多相关文章
- [luogu P1552] [APIO2012]派遣
[luogu P1552] [APIO2012]派遣 题目背景 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿. 题目描述 在这个帮派里,有一名忍者被称之为Master.除 ...
- 洛谷P1552 [APIO2012] 派遣 [左偏树,树形DP]
题目传送门 忍者 Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都 ...
- luogu P1552 [APIO2012]派遣 题解--可并堆/贪心
题目链接: https://www.luogu.org/problemnew/show/P1552 分析: 一开始愣是没看懂题,后面发现就是你要找一个树上点集使得各点权值之和小于\(M\),并且找一个 ...
- Luogu P1552 [APIO2012]派遣 主席树
题目链接 Click Here 这个题好像大多数人用的都是左偏树啊?这里我来贡献一发主席树的解法. 把题目中的问题抽象出来,其实就是询问每一个点的子树中,工资前\(tot_i\)大的点,使它们的和满足 ...
- 2018.07.31洛谷P1552 [APIO2012]派遣(可并堆)
传送门 貌似是个可并堆的模板题,笔者懒得写左偏堆了,直接随机堆水过.实际上这题就是维护一个可合并的大根堆一直从叶子合并到根,如果堆中所有数的和超过了上限就一直弹直到所有数的和不超过上限为止,最后对于当 ...
- [洛谷P1552][APIO2012]派遣
题目大意:有一棵$n$个点的树,和一个费用$m$,每个点有一个费用和价值,请选一个点,再从它的子树中选取若干个点,使得那个点的价值乘上选的点的个数最大,要求选的点费用总和小于等于$m$ 题解:树形$d ...
- Luogu P1552 [APIO2012]派遣【左偏树】By cellur925
题目传送门 $Chat$ 哈哈哈我xj用dfs序乱搞竟然炸出了66分....(其实还是数据水,逃) $Sol$ 首先我们应该知道,一个人他自己的满意度与他子树所有节点的领导力是无关的,一个人的满意度受 ...
- 洛谷P1552 [APIO2012]派遣(左偏树)
传送门 做这题的时候现学了一波左偏树2333(好吧其实是当初打完板子就给忘了) 不难发现肯定是选子树里权值最小的点且选得越多越好 但如果在每一个点维护一个小根堆,我们得一直找知道权值大于m为止,时间会 ...
- [洛谷P1552] [APIO2012]派遣(左偏树)
这道题是我做的左偏树的入门题,奈何还是看了zsy大佬的题解才能过,唉,我太弱了. 左偏树总结 Part 1 理解题目 很显然,通过管理关系的不断连边,最后连出来的肯定是一棵树,那么不难得出,当一个忍者 ...
随机推荐
- caffe中关于(ReLU层,Dropout层,BatchNorm层,Scale层)输入输出层一致的问题
在卷积神经网络中.常见到的激活函数有Relu层 layer { name: "relu1" type: "ReLU" bottom: "pool1&q ...
- strlen实现
1.strlen函数. 普通版实现方法, int strlen( char *s) { int length = 0; while(*s++) length++; return length; } 优 ...
- ueditor上传图片配置成功,但是如何删除无用的图片
我使用ueditor作为富文本编辑器,配置已经好了,上传功能也好了.现在的问题是当使用ueditor上传图片的时候,选择了图片就立刻上传到指定的文件夹里,而后续即使没有保存该篇文章内容,即取消操作,图 ...
- WebStorage (1) 实例
实例代码 <p>本页面每5秒刷新一下,这是您第<mark></mark>次进入本页面!</p> <script> if (window.lo ...
- html5-内联框架
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&qu ...
- mysql 对表字段进行长度截取操作
现在的问题是数据库某一个表中其中的车牌号字段有些数据多了一位,需要把它找出来然后把多的最后一位去掉..... 通过自带的length(字段名)函数把长度过长的数据过滤出来,其中,一个汉字算3个字符,一 ...
- GCD(III)
GCD 线程间的通信 在iOS开发过程中,我们一般在主线程里边进行UI刷新,例如:点击.滚动.拖拽等事件.我们通常把一些耗时的操作放在其他线程,比如说图片下载.文件上传等耗时操作.而当我们有时候在其他 ...
- 网站图标 favicon.ico
默认情况下,浏览器访问一个网站的时候,同时还会向服务器请求“/favicon.ico”这个URL,目的是获取网站的图标. 若没有配置的话,Django就会返回一个404错误,并且浏览器接收到这个404 ...
- Linux基础命令---文本显示tac
tac 将指定文件中的行,按照反序方式显示.此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.SUSE.openSUSE.Fedora. 1.语法 tac [选项] ...
- linux screen 多任务后台执行
1.安装工具:yum install -y screen 2.进入新screen界面:screen 3.回到原命令行:先按CTRL+a,然后再按d 4.查看现有的screen回话:screen -ls ...