链接

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. netcore webapi统一配置跨域问题

    修改startup类中的configure方法

  2. jquer文字闪烁简单实现

    arguments.callee <script type="text/javascript"> (function () { $(".usesend&quo ...

  3. 本地文件直接访问html,document.cookie总是显示空字符串

    当file:///E:/browser.html访问时,我们设置document.cookie,读取时一直会显示空字符串! 而开一下Apache时:localhost/browser.html或者12 ...

  4. MySql获取两个日期间的时间差

    [1]MySql 语言获取两个日期间的时间差 DATEDIFF 函数可以获得两个日期之间的时间差.但是,这个函数得出的结果是天数. 需要直接获取秒数可使用TIMESTAMPDIFF函数.应用示例如下: ...

  5. A stock

    1. 密集成交不太妙 主力抛压退为好

  6. 2018年Android面试题含答案--适合中高级

    1.java中==和equals和hashCode的区别  基本数据类型的==比较的值相等. 类的==比较的内存的地址,即是否是同一个对象,在不覆盖equals的情况下,同比较内存地址,原实现也为 = ...

  7. js如何获取服务器端时间?

    用js做时间校正,获取本机时间,是存在bug的. 使用js也可获取到服务器时间,原理是使用 ajax请求,返回的头部信息就含有服务器端的时间信息,获取到就可以了.以下: 1.依赖jQuery 代码: ...

  8. javanio2

    package com.lanhuigu.nio.selector; import java.net.InetSocketAddress; import java.nio.ByteBuffer; im ...

  9. <转>jmeter(十一)JDBC Request之Query Type

    本博客转载自:http://www.cnblogs.com/imyalost/category/846346.html 个人感觉不错,对jmeter讲解非常详细,担心以后找不到了,所以转发出来,留着慢 ...

  10. 爬虫之牛掰的scrapy框架

    一. Scrapy简介及安装 http://python.jobbole.com/86405/ Scrapy的详细介绍   1.简介   2.安装     1.window上安装:         先 ...