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

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

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

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

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

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

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

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

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

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

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

  6. 题解 洛谷 P1552 【[APIO2012]派遣】

    根据题意,我们不难发现忍者之间的关系是树形结构. 发现答案的统计只是在该节点的子树中,因此我们考虑通过树形\(DP\)来解决问题. 从叶子节点开始,从下往上考虑,因为一个节点的最优答案只与他的领导力和 ...

  7. 洛谷 - P1552 - 派遣 - 左偏树 - 并查集

    首先把这个树建出来,然后每一次操作,只能选中一棵子树.对于树根,他的领导力水平是确定的,然后他更新答案的情况就是把他子树内薪水最少的若干个弄出来. 问题在于怎么知道一棵子树内薪水最少的若干个分别是谁. ...

  8. 洛谷 [P1552] 派遣

    树型DP + 可并堆 非常清楚的想到是树型DP, 但是如何维护最小值, 于是就去新学了可并堆 #include <iostream> #include <cstring> #i ...

  9. 洛谷1552 [APIO2012]派遣

    洛谷1552 [APIO2012]派遣 原题链接 题解 luogu上被刷到了省选/NOI- ...不至于吧 这题似乎有很多办法乱搞? 对于一个点,如果他当管理者,那选的肯定是他子树中薪水最少的k个,而 ...

随机推荐

  1. Zip加密解密

    Zip加密解密方法: 1.winzipaes http://blog.csdn.net/zhyh1986/article/details/7724229 2.zip4j http://blog.csd ...

  2. LCS的几种求法

    \(LCS:\) 对于两个长度均为 \(N\) 的数列 \(A\) 和 \(B\) ,存在一个数列 \(C\) 使得 \(C\) 既是 \(A\) 的子序列有事 \(B\) 的子序列,现在需要求这个数 ...

  3. 记录001:AS11 BAPI

    未知元素(174657434)  15:05:41AS11有没有BAPI呀?有做过的吗 BAPI_FIXEDASSET_OVRTAKE_CREATE

  4. ios实现倒计时的两种方法

    方法1:使用NSTimer来实现 主要使用的是NSTimer的scheduledTimerWithTimeInterval方法来每1秒执行一次timeFireMethod函数,timeFireMeth ...

  5. vfork函数的使用【学习笔记】

    #include "apue.h" ; int main(void) { int var; pid_t pid; ; printf("before vfork\r\n&q ...

  6. poj 1860 Currency Exchange 解题报告

    题目链接:http://poj.org/problem?id=1860 题目意思:给出 N 种 currency, M种兑换方式,Nick 拥有的的currency 编号S 以及他的具体的curren ...

  7. wukong引擎源码分析之搜索——docid有序的数组里二分归并求交集,如果用跳表的话,在插入索引时会更快

    searcher.Search(types.SearchRequest{Text: "百度中国"}) // 查找满足搜索条件的文档,此函数线程安全 func (engine *En ...

  8. 子元素margin带动父元素拖动

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. uCareSystem:Ubuntu/Linux Mint的一体化系统更新和维护工具

    对于任何一款允许用户还原电脑到之前状态(包括文件系统,安装的应用,以及系统设置)的操作系统来说,系统还原功能都是必备功能,它可以恢复系统故障以及其他的问题. 有的时候安装一个程序或者驱动可能让你的系统 ...

  10. Python之路,Day13 - 堡垒机

    项目实战:运维堡垒机开发 前景介绍 到目前为止,很多公司对堡垒机依然不太感冒,其实是没有充分认识到堡垒机在IT管理中的重要作用的,很多人觉得,堡垒机就是跳板机,其实这个认识是不全面的,跳板功能只是堡垒 ...