[APIO2012]派遣 洛谷P1552 bzoj2809 codevs1763
http://www.codevs.cn/problem/1763/
https://www.lydsy.com/JudgeOnline/problem.php?id=2809
https://www.luogu.org/problemnew/show/P1552
http://210.33.19.101/problem/2182
用线段树合并,值域线段树维护可重集合,线段树每个节点维护一个sum表示当前集合中,所有在范围[l,r](这个点的值域区间)内的数的和;每个点从其子节点合并;查询就根据左子节点sum与当前最大允许的和决定往左还是往右走
话说稍微有点卡空间。。。(加了内存回收,然而理论上内存回收应该并不能改进最坏空间复杂度)
看了题解,发现只要暴力启发式合并/可并堆,合并完成后暴力删除最大值直到合法就行了。。。(因为每个点只会被删一次)
又想了想,只要暴力普通堆启发式合并就行了。。。。40行就行。。。
#pragma GCC optimize(3)//不开优化可能被卡常
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#define pb push_back
using namespace std;
typedef long long LL;
int n,m;
vector<int> ch[];
int c[],l[],fa[];
LL sum[];
priority_queue<int> q[];
LL ans;
void dfs(int u)
{
int i,v;
q[u].push(c[u]);sum[u]+=c[u];
for(i=;i<ch[u].size();i++)
{
v=ch[u][i];
dfs(v);
if(q[v].size()>q[u].size()) swap(q[u],q[v]);
while(!q[v].empty()) q[u].push(q[v].top()),q[v].pop();
sum[u]+=sum[v];
}
while(sum[u]>m) sum[u]-=q[u].top(),q[u].pop();
ans=max(ans,l[u]*LL(q[u].size()));
}
int main()
{
int i,a;
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
{
scanf("%d%d%d",&a,&c[i],&l[i]);
fa[i]=a;ch[a].pb(i);
}
dfs();
printf("%lld",ans);
return ;
}
空间因为pq里面用了vector之类的好像会被卡。。。可以改一下
#pragma GCC optimize(3)//不开优化可能被卡常
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#define pb push_back
using namespace std;
typedef long long LL;
int n,m;
vector<int> ch[];
int c[],l[],fa[];
LL sum[];
priority_queue<int> *q[];
LL ans;
void dfs(int u)
{
int i,v;q[u]=new priority_queue<int>();
q[u]->push(c[u]);sum[u]+=c[u];
for(i=;i<ch[u].size();i++)
{
v=ch[u][i];
dfs(v);
if(q[v]->size()>q[u]->size()) swap(q[u],q[v]);
while(!q[v]->empty()) q[u]->push(q[v]->top()),q[v]->pop();
sum[u]+=sum[v];delete q[v];
}
while(sum[u]>m) sum[u]-=q[u]->top(),q[u]->pop();
ans=max(ans,l[u]*LL(q[u]->size()));
}
int main()
{
int i,a;
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
{
scanf("%d%d%d",&a,&c[i],&l[i]);
fa[i]=a;ch[a].pb(i);
}
dfs();
printf("%lld",ans);
return ;
}
错误记录:答案没有开longlong所以无限WA
#include<cstdio>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;
typedef long long LL;
namespace S
{
#define mid (l+((r-l)>>1))
#define N 3000000
int dat[N],lc[N],rc[N];LL sum[N];
int L;
int st[N+],top;
void init()
{
int i;
for(i=;i<N;i++) st[++top]=i;
}
int getnode()
{
int t=st[top--];dat[t]=sum[t]=lc[t]=rc[t]=;
return t;
}
void delnode(int x) {st[++top]=x;}
void _addx(int l,int r,int &num)
{
if(!num) num=getnode();
if(l==r) {dat[num]++;sum[num]+=l;return;}
if(L<=mid) _addx(l,mid,lc[num]);
else _addx(mid+,r,rc[num]);
dat[num]=dat[lc[num]]+dat[rc[num]];
sum[num]=sum[lc[num]]+sum[rc[num]];
}
void addx(int p,int &num)
{
L=p;_addx(,1e9,num);
}
int merge(int a,int b)
{
if(!a||!b) return a+b;
lc[a]=merge(lc[a],lc[b]);
rc[a]=merge(rc[a],rc[b]);
dat[a]+=dat[b];
sum[a]+=sum[b];
delnode(b);
return a;
}
int find(int l,int r,int num,LL msum)
{
if(l==r) return msum/l;
if(sum[lc[num]]>=msum) return find(l,mid,lc[num],msum);
else return find(mid+,r,rc[num],msum-sum[lc[num]])+dat[lc[num]];
}
#undef mid
}
vector<int> ch[];
int n,m;
int c[],l[],fa[];
int rt[];LL ans;
void dfs(int u)
{
S::addx(c[u],rt[u]);
for(int i=,v;i<ch[u].size();i++)
{
v=ch[u][i];
dfs(v);
rt[u]=S::merge(rt[u],rt[v]);
}
ans=max(ans,LL(l[u])*S::find(,1e9,rt[u],m));
}
int main()
{
int i,a;S::init();
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
{
scanf("%d%d%d",&a,&c[i],&l[i]);
fa[i]=a;ch[a].pb(i);
}
dfs();
printf("%lld",ans);
return ;
}
[APIO2012]派遣 洛谷P1552 bzoj2809 codevs1763的更多相关文章
- 洛谷P1552 [APIO2012] 派遣 [左偏树,树形DP]
题目传送门 忍者 Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都 ...
- 2018.07.31洛谷P1552 [APIO2012]派遣(可并堆)
传送门 貌似是个可并堆的模板题,笔者懒得写左偏堆了,直接随机堆水过.实际上这题就是维护一个可合并的大根堆一直从叶子合并到根,如果堆中所有数的和超过了上限就一直弹直到所有数的和不超过上限为止,最后对于当 ...
- [洛谷P1552][APIO2012]派遣
题目大意:有一棵$n$个点的树,和一个费用$m$,每个点有一个费用和价值,请选一个点,再从它的子树中选取若干个点,使得那个点的价值乘上选的点的个数最大,要求选的点费用总和小于等于$m$ 题解:树形$d ...
- 洛谷P1552 [APIO2012]派遣(左偏树)
传送门 做这题的时候现学了一波左偏树2333(好吧其实是当初打完板子就给忘了) 不难发现肯定是选子树里权值最小的点且选得越多越好 但如果在每一个点维护一个小根堆,我们得一直找知道权值大于m为止,时间会 ...
- [洛谷P1552] [APIO2012]派遣(左偏树)
这道题是我做的左偏树的入门题,奈何还是看了zsy大佬的题解才能过,唉,我太弱了. 左偏树总结 Part 1 理解题目 很显然,通过管理关系的不断连边,最后连出来的肯定是一棵树,那么不难得出,当一个忍者 ...
- 题解 洛谷 P1552 【[APIO2012]派遣】
根据题意,我们不难发现忍者之间的关系是树形结构. 发现答案的统计只是在该节点的子树中,因此我们考虑通过树形\(DP\)来解决问题. 从叶子节点开始,从下往上考虑,因为一个节点的最优答案只与他的领导力和 ...
- 洛谷 - P1552 - 派遣 - 左偏树 - 并查集
首先把这个树建出来,然后每一次操作,只能选中一棵子树.对于树根,他的领导力水平是确定的,然后他更新答案的情况就是把他子树内薪水最少的若干个弄出来. 问题在于怎么知道一棵子树内薪水最少的若干个分别是谁. ...
- 洛谷 [P1552] 派遣
树型DP + 可并堆 非常清楚的想到是树型DP, 但是如何维护最小值, 于是就去新学了可并堆 #include <iostream> #include <cstring> #i ...
- 洛谷1552 [APIO2012]派遣
洛谷1552 [APIO2012]派遣 原题链接 题解 luogu上被刷到了省选/NOI- ...不至于吧 这题似乎有很多办法乱搞? 对于一个点,如果他当管理者,那选的肯定是他子树中薪水最少的k个,而 ...
随机推荐
- 浅谈HTTPS连接
相信很多朋友都遇到过网页被强插广告的情况,好端端一个干净的页面,动不动就被插了个屠龙宝刀点击就送的小窗口,看着就心烦.这种网页劫持强插广告的现象,在中国非常常见,往往是运营商进行HTTP劫持所造成的. ...
- if return 和 if else
最近看Node.js实战中,有一段代码是优化之前使用if else,优化之后是使用if return,我不知道if return是不是效率比if else高. 优化前: if(err){ handle ...
- Hadoop 文件压缩
一.目的 a. 减小磁盘占用 b. 加速网络IO 二.几个常用压缩算法 是否可切分:是指压缩后的文件能否支持在任意位置往后读取数据. 各种压缩格式特点: 压缩算法都需要权衡 空间/时间 :压缩率越高, ...
- Why is an 'Any CPU' application running as x86 on a x64 machine?
It's likely that you linked some assemblies that are not Any CPU, but include native code (or are ...
- 【转】Java数字抽奖游戏核心代码
1. [代码][Java]代码 package com.luiszhang.test; import java.util.Arrays; /** * NumberLotteryGame * 一个 ...
- 深入浅出Oracle学习笔记:Undo
undo的作用是:解决oracle多用户读写一致性,以及操作可撤销或者回滚. 1.undo表空间是从10g开始进行自动管理的,几个参数如下: undo_management:回滚段手动管理还是自动管理 ...
- codeforces 690D2 D2. The Wall (medium)(组合数学)
题目链接: D2. The Wall (medium) time limit per test 2 seconds memory limit per test 256 megabytes input ...
- codeforces 667B B. Coat of Anticubism(水题)
题目链接: B. Coat of Anticubism time limit per test 1 second memory limit per test 256 megabytes input s ...
- VS 一些配置设置
/************************************************************************ * VS 一些配置设置 * 说明: * 最近要用到C ...
- [Java] 读取文件
1.按字节读取文件内容2.按字符读取文件内容3.按行读取文件内容 4.随机读取文件内容 public class ReadFromFile { /** * 以字节为单位读取文件,常用于读二进制文件,如 ...