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;
}

最新文章

  1. Linux 操作mysql数据库 创建库 导入、删除表
  2. Spring MVC 框架的架包分析,功能作用,优点
  3. ios编码转换 国标 UTF-8
  4. easyui datagrid 多行删除问题
  5. 【性能诊断】十、性能问题综合分析(案例1,windbg、Network Monitor)
  6. libthrift0.9.0解析(五)之TNonblockingServer&amp;THsHaServer
  7. Android推送等耗电原因剖析
  8. [TYVJ] P1006 ISBN
  9. visual studio 2013 使用IIS Express附加调试MVC5
  10. java在string和int相互转化
  11. MVC+Front Controller
  12. sync命令
  13. mysql、mysqli、pdo使用
  14. LVS负载均衡介绍
  15. String,StringBuffer与StringBuilder的区别?? 缓存
  16. 从零开始搭建Android组件化框架
  17. 19-03【golang】strings包
  18. redis key的过期时间
  19. 【iCore1S 双核心板_FPGA】例程六:状态机实验——状态机使用
  20. 【PyQt5-Qt Designer】简易的数字键盘输入+简易计算器

热门文章

  1. Nginx 缓存命中率
  2. PgSQL备份
  3. ZYNQ入门实例——三种GPIO应用、中断系统及软硬件交叉触发调试
  4. 基于webpack的vue开发环境搭建
  5. Failed to get convolution algorithm解决
  6. SignalR—实例
  7. 进阶之路 | 奇妙的Drawable之旅
  8. SOLID原则都不知道,还敢说自己是搞开发的!
  9. window 下如何恢复被删除的mysql root账户及密码(mysql 8.0.17)
  10. 使用 linux kernel +busybox 定制linux系统