链接

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]派遣的更多相关文章

  1. [luogu P1552] [APIO2012]派遣

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

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

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

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

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

  4. Luogu P1552 [APIO2012]派遣 主席树

    题目链接 Click Here 这个题好像大多数人用的都是左偏树啊?这里我来贡献一发主席树的解法. 把题目中的问题抽象出来,其实就是询问每一个点的子树中,工资前\(tot_i\)大的点,使它们的和满足 ...

  5. 2018.07.31洛谷P1552 [APIO2012]派遣(可并堆)

    传送门 貌似是个可并堆的模板题,笔者懒得写左偏堆了,直接随机堆水过.实际上这题就是维护一个可合并的大根堆一直从叶子合并到根,如果堆中所有数的和超过了上限就一直弹直到所有数的和不超过上限为止,最后对于当 ...

  6. [洛谷P1552][APIO2012]派遣

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

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

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

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

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

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

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

随机推荐

  1. python中impyla包报'TSocket' object has no attribute 'isOpen'错误

    经搜索得知,是thrift-sasl的版本太高了(0.3.0),故将thrift-sasl的版本降级到0.2.1 pip install thrift-sasl==0.2.1 经测试impyla 可以 ...

  2. C#操作XML方法详解

    using System.Xml; //初始化一个xml实例 XmlDocument xml=new XmlDocument();   //导入指定xml文件 xml.Load(path); xml. ...

  3. [博客迁移]探索Windows Azure 监控和自动伸缩系列3 - 启用Azure监控扩展收集自定义监控数据

    上一篇我们介绍了获取Azure的监控指标和监控数据: http://www.cnblogs.com/teld/p/5113376.html 本篇我们继续:监控虚拟机的自定义性能计数器. 随着我们应用规 ...

  4. Qt信号之自定义数据类型

    [1]为什么需要自定义数据类型? 内置类型毕竟很有局限性,否则为什么还需要类呢.总之,有时候,我们多么希望信号能发送自定义数据类型. 幸哉~ Qt是支持自定义信号,且自定义信号可以发送自定义数据类型的 ...

  5. Spring 默认的 AopProxy

    Spring 默认的 AopProxy JdkDynamicAopProxy Spring xml 文件默认解析器 DefaultDocumentLoader 采用 standard JAXP-con ...

  6. Python 构造一个可接受任意数量参数的函数

    为了能让一个函数接受任意数量的位置参数,可以使用一个* 参数 在这个例子中,rest 是由所有其他位置参数组成的元组.然后我们在代码中把它当成了一个序列来进行后续的计算

  7. 转:【专题十二】实现一个简单的FTP服务器

    引言: 休息一个国庆节后好久没有更新文章了,主要是刚开始休息完心态还没有调整过来的, 现在差不多进入状态了, 所以继续和大家分享下网络编程的知识,在本专题中将和大家分享如何自己实现一个简单的FTP服务 ...

  8. 转:【专题六】UDP编程

    引用: 前一个专题简单介绍了TCP编程的一些知识,UDP与TCP地位相当的另一个传输层协议,它也是当下流行的很多主流网络应用(例如QQ.MSN和Skype等一些即时通信软件传输层都是应用UDP协议的) ...

  9. Deploying docker registry v2

    生成证书 openssl genrsa -out mydomain.key 2048 生成秘钥 openssl req -newkey rsa:4096 -nodes -sha256 -keyout ...

  10. LINUX搭建PySpider爬虫服务

    1.环境搭建 yum update -y yum install gcc gcc-c++ -y yum install python-pip python-devel python-distribut ...