BZOJ2809&&LG1552 APIO2012派遣(线段树合并)

题面

自己找去

HINT

简化一题面就是让你从每个点的子树中以\(<=m\)的代价选取尽可能多的点,然后乘上子树根的一个属性值,每个点做一遍取个\(max\)。看大家都是什么可并堆、dfs序+主席树,我的做法是对于每个节点开一颗权值线段树,每个节点维护\(size\)和\(tot\),然后修改和线段树合并都是常规写法。

着重讲一下查询

这样的写法之后就是要实现查询用m的代价可以最多选择多少个点

inline int query(int p,long long rk,int l,int r){
if(!p) return 0;//如果进入了空节点,就肯定没有可选的,返回0
if(l==r){
int x=st[p].tot/st[p].size;return min((long long)rk/x,(long long)st[p].size);
//这里是重点,查询到该点的时候我还有rk的剩余,已经到叶子节点了,这个时候我们就要计算一下自己最多可以选多少个,如果能都选就都选,如果不能多选就尽量选满
}
long long now=st[ls(p)].tot;int mid=(l+r)>>1;
if(rk<=now) return query(ls(p),rk,l,mid);
else return st[ls(p)].size+query(rs(p),rk-now,mid+1,r);
}

其他的看代码吧

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ls(x) st[x].ch[0]
#define rs(x) st[x].ch[1]
using namespace std;
inline int read(){
int w=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
w=(w<<3)+(w<<1)+ch-48;
ch=getchar();
}
return w*f;
}
int n,m,cur,root[100010],a[100010],b[100010],val[100010],now[100010];
long long l[100010],ans[100010];
bool debug;
struct CHAIRMANTREE{
struct Node{
int size,ch[2];long long tot;
}st[6000010];
int tot;
inline void pushup(int x){
st[x].size=st[ls(x)].size+st[rs(x)].size;
st[x].tot=st[ls(x)].tot+st[rs(x)].tot;return;
}
inline int change(int p,int l,int r,int pos,int val){
if(!p)p=++tot;
if(l==r){
st[p].size+=1;st[p].tot+=val;return p;
}
int mid=(l+r)>>1;
if(pos<=mid) ls(p)=change(ls(p),l,mid,pos,val);
else rs(p)=change(rs(p),mid+1,r,pos,val);
pushup(p);return p;
}
inline int merge(int x,int y,int l,int r){
if(!x||!y) return x|y;
int p=++tot;
if(l==r){
st[p].size=st[x].size+st[y].size;
st[p].tot=st[x].tot+st[y].tot;return p;
}
int mid=(l+r)>>1;
ls(p)=merge(ls(x),ls(y),l,mid);
rs(p)=merge(rs(x),rs(y),mid+1,r);
pushup(p);return p;
}
inline int query(int p,long long rk,int l,int r){
if(!p) return 0;
if(l==r){
int x=st[p].tot/st[p].size;return min((long long)rk/x,(long long)st[p].size);
}
long long now=st[ls(p)].tot;int mid=(l+r)>>1;
if(rk<=now) return query(ls(p),rk,l,mid);
else return st[ls(p)].size+query(rs(p),rk-now,mid+1,r);
}
}TREE;
int cnt,head[100010];
struct Edge{
int from,to,next;
}edge[200010];
inline void addedge(int u,int v){
cnt++;
edge[cnt].from=u;
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt;
}
map<int,int> mapp;
inline void prework(){
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
if(!mapp[a[i]]){
cur++;mapp[a[i]]=cur;b[cur]=a[i];
}
}
for(int i=1;i<=n;i++){
val[i]=mapp[val[i]];
}
}
inline void dfs(int u){
root[u]=TREE.change(root[u],1,cur,val[u],now[u]);
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;dfs(v);
root[u]=TREE.merge(root[u],root[v],1,cur);
}
if(debug)cout<<"test"<<u<<endl;
ans[u]=(long long)TREE.query(root[u],m,1,cur);
if(debug){
cout<<u<<" "<<ans[u]<<endl;
}
}
signed main(){
n=read();m=read();
for(int i=1;i<=n;i++){
int x=read();addedge(x,i);
now[i]=a[i]=val[i]=read();l[i]=read();
}
prework();
//debug=true;
dfs(1);
long long Ans=-1;
for(int i=1;i<=n;i++){
//cout<<l[i]<<" "<<ans[i]<<endl;
Ans=max(Ans,l[i]*ans[i]);
}
cout<<Ans<<endl;
return 0;
}

BZOJ2809&&LG1552 APIO2012派遣(线段树合并)的更多相关文章

  1. [XJOI NOI2015模拟题13] C 白黑树 【线段树合并】

    题目链接:XJOI - NOI2015-13 - C 题目分析 使用神奇的线段树合并在 O(nlogn) 的时间复杂度内解决这道题目. 对树上的每个点都建立一棵线段树,key是时间(即第几次操作),动 ...

  2. [BZOJ 2212] [Poi2011] Tree Rotations 【线段树合并】

    题目链接:BZOJ - 2212 题目分析 子树 x 内的逆序对个数为 :x 左子树内的逆序对个数 + x 右子树内的逆序对个数 + 跨越 x 左子树与右子树的逆序对. 左右子树内部的逆序对与是否交换 ...

  3. BZOJ 3307: 雨天的尾巴( LCA + 线段树合并 )

    路径(x, y) +z : u处+z, v处+z, lca(u,v)处-z, fa(lca)处-z, 然后dfs一遍, 用线段树合并. O(M log M + M log N). 复杂度看起来不高, ...

  4. BZOJ2733 [HNOI2012]永无乡 【线段树合并】

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  5. bzoj 2243 [SDOI2011]染色(树链剖分+线段树合并)

    [bzoj2243][SDOI2011]染色 2017年10月20日 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询 ...

  6. bzoj3702二叉树 线段树合并

    3702: 二叉树 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 600  Solved: 272[Submit][Status][Discuss] ...

  7. BZOJ_2212_[Poi2011]Tree Rotations_线段树合并

    BZOJ_2212_[Poi2011]Tree Rotations_线段树合并 Description Byteasar the gardener is growing a rare tree cal ...

  8. B20J_2733_[HNOI2012]永无乡_权值线段树合并

    B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...

  9. BZOJ_3307_雨天的尾巴_线段树合并+树上差分

    BZOJ_3307_雨天的尾巴_线段树合并 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后 ...

随机推荐

  1. 如何开始阅读ASP.NET Core源代码

    背景 当我们对ASP.Net Core内部的某些方法.类的实现感兴趣时,有很多方法可以去了解,看书,看各种文章,但是最直接也是最深入的办法就是去阅读源代码.ASP.NET Core的源代码托管在Git ...

  2. 跨域的两种解决方法jsonp和CORS

    1.跨域 什么是跨域? 当你请求的url是不同源的数据的时候,浏览器一般会抛出请求跨域的错误,如下图: 造成跨域的原因? 即你违反了浏览器的同源策略的限制=>阻止一个域的js脚本和另外一个域的内 ...

  3. Kafka运维大全来了!优化、监控、故障处理……

      Kafka概念   Kafka是分布式发布-订阅消息系统.它最初由LinkedIn公司开发,之后成为Apache项目的一部分.Kafka是一个分布式的.可划分的.冗余备份的.持久性的日志服务.它主 ...

  4. Angular组件通信

    一. 组件间通信(组件间不能互相调用,公共方法放在服务中) (目前项目采用将公共方法直接写在ts文件中没使用服务) ng g service services/服务名 App.module.ts{ 引 ...

  5. React之this绑定

    一.首先看一下没有绑定this的情况 class App extends React.Component{ constructor(props){ super(props) console.log(' ...

  6. 2,简单的Python爬虫

    前言 根据上一篇 1,Python爬虫环境的安装我们已经在本地安装好了Python环境,那么这一篇就开始学习如何用Python来爬虫! 环境:操作系统:Windows10 IDE:   PyCharm ...

  7. everspin最新1Gb容量扩大MRAM吸引力

    everspin提供了8/16-bit的DDR4-1333MT/s(667MHz)接口,但与较旧的基于DDR3的MRAM组件一样,时序上的差异使得其难以成为DRAM(动态随机存取器)的直接替代品.   ...

  8. #《Essential C++》读书笔记# 第一章 C++ 编程基础

    前言 Stanley B.Lippman 先生所著的<C++ Primer>是学习C++的一本非常优秀的教科书,但<C++ Primer>作为一本大部头书,显然不适合所有的初学 ...

  9. 数据库自学笔记(2)--- HAVING和WHERE, ANY 和 ALL,IN和EXIST。

    1.HAVING和WHERE: WHERE 和 HAVING 的作用对象不一样.WHERE作用于基本表或视图,挑出满足条件的元组.HAVING作用于组(group),一般配合GROUP BY 使用. ...

  10. day16 匿名函数

    # 匿名函数# 函数名 = lambda 参数1,(参数2,....) : 返回值 [注意:匿名函数不允许换行]# 匿名函数返回值和正常函数一样可以是任意数据类型# def add(x,y):# re ...