题解 NOI2004【郁闷的出纳员】
\]
之前用 treap 打,交了四遍才过。
自学了 fhq treap 后,才意识到是一道 fhq treap 板子题,直接码上,一遍就过。
本题解提供的是 fhq treap 做法(感谢 fhq 神犇),不太了解 fhq treap 的同学可以去了解一下 fhq treap ,挺好理解的。(至少要了解两种 split 和 merge 操作)
\]
你需要维护一个可重集,支持 \(4\) 种操作:
I k向集合内插入元素 \(k\) 。
A k将集合内所有元素加上 \(k\) 。
S k将集合内所有元素减去 \(k\) 。
F k查询集合内第 \(k\) 大。
一共 \(n\) 次操作。
一开始给出一个下界 \(Minv\) ,表示集合内的所有元素必须大于等于 \(Minv\) ,在任何时刻,小于 \(Minv\) 的所有元素会被立刻删除。
最后还要输出被删除的元素个数。
\]
对于 I k 操作:
首先先判断一下 \(k\) 是否大于等于 \(Minv\) ,之后就是经典的插入操作了。
让原树按 \(k-1\) 值分裂成两棵树 \(x,y\) ,新建值为 \(k\) 的节点 \(New\) ,合并 \(x,New,y\) 。
\(~\)
对于 A k 和 S k 操作:
考虑到 " A 和 S 命令的总条数不超过 100 " ,想到了啥?暴力修改!
显然集合内的所有元素加上 \(k\) 或减去 \(k\),fhq treap 树形态不变。
A k 操作就很好办了,集合内的所有元素加上 \(k\) 固然还是大于等于 \(Minv\) ,直接 \(dfs\) 暴力修改即可。
S k 操作之后还会导致一些元素小于 \(Minv\) ,这些元素在还没操作前是小于 \(Minv+k\) 的。
那么我们可以将原树按 \(Minv+k-1\) 值分裂成两棵树 \(x,y\) 。树 \(x\) 的所有元素在操作之后都是小于 \(Minv\) 的,那么此次被删除的元素个数即为 \(size[x]\) ,将其累加进答案,随后树 \(x\) 就没有用了,不用管它就行了。树 \(y\) 的所有元素在操作之后都是大于等于 \(Minv\) 的,直接 \(dfs\) 暴力修改,最后将树 \(y\) 当成原树就行了。
\(~\)
对于 F k 操作:
经典的查询第 \(k\) 大。
让原树按 \(size[root]-k\) 大小分裂成两棵树 \(x,y\) ,再让树 \(y\) 按 \(1\) 大小分裂成两棵树 \(y,z\) ,此时树 \(y\) 只有一个节点,这个节点就是我们要找的第 \(k\) 大了,最后记得合并回去。
当然,在 " 按大小分裂 " 上做一点小改动,或是用一般 treap 的查询第 k 大也是可以的。
\(~\)
至此,此题得到完美解决。
\]
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define RI register int
using namespace std;
inline int read()
{
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
return x*f;
}
const int N=100100;
int m,Minv;
int tot,root;
struct treap{
int lc,rc;
int val,dat;
int size;
}t[N];
int New(int val)
{
tot++;
t[tot].lc=t[tot].rc=0;
t[tot].val=val;
t[tot].dat=rand();
t[tot].size=1;
return tot;
}
void upd(int p)
{
t[p].size=t[t[p].lc].size+t[t[p].rc].size+1;
}
void split_v(int p,int val,int &x,int &y)
{
if(!p)
x=y=0;
else
{
if(t[p].val<=val)
x=p,split_v(t[p].rc,val,t[p].rc,y);
else
y=p,split_v(t[p].lc,val,x,t[p].lc);
upd(p);
}
}
void split_s(int p,int size,int &x,int &y)
{
if(!p)
x=y=0;
else
{
if(t[t[p].lc].size<size)
x=p,split_s(t[p].rc,size-t[t[p].lc].size-1,t[p].rc,y);
else
y=p,split_s(t[p].lc,size,x,t[p].lc);
upd(p);
}
}
int merge(int p,int q)
{
if(!p||!q)
return p^q;
if(t[p].dat>t[q].dat)
{
t[p].rc=merge(t[p].rc,q),upd(p);
return p;
}
else
{
t[q].lc=merge(p,t[q].lc),upd(q);
return q;
}
}
int x,y,z;
void insert(int val)
{
split_v(root,val-1,x,y);
root=New(val);
root=merge(x,root);
root=merge(root,y);
}
void dfs(int u,int val)
{
if(!u)return;
t[u].val+=val;
dfs(t[u].lc,val),dfs(t[u].rc,val);
}
int GetValByRank(int rank)
{
if(t[root].size<rank)
return -1;
split_s(root,t[root].size-rank,x,y);
split_s(y,1,y,z);
int ans=t[y].val;
root=merge(x,y);
root=merge(root,z);
return ans;
}
int ans;
int main()
{
m=read(),Minv=read();
while(m--)
{
char op[2];scanf("%s",op);
int val=read();
switch(op[0])
{
case 'I':{
if(Minv<=val)
insert(val);
break;
}
case 'A':{
dfs(root,val);
break;
}
case 'S':{
split_v(root,Minv+val-1,x,root);
ans+=t[x].size;
dfs(root,-val);
break;
}
case 'F':{
printf("%d\n",GetValByRank(val));
break;
}
}
}
printf("%d\n",ans);
return 0;
}
\]
题解 NOI2004【郁闷的出纳员】的更多相关文章
- [BZOJ1503][NOI2004]郁闷的出纳员
[BZOJ1503][NOI2004]郁闷的出纳员 试题描述 OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是 ...
- BZOJ 1503: [NOI2004]郁闷的出纳员 splay
1503: [NOI2004]郁闷的出纳员 Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作 ...
- [BZOJ1503][NOI2004]郁闷的出纳员 无旋Treap
1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec Memory Limit: 64 MB Description OIER公司是一家大型专业化软件公司,有着数以万计的员 ...
- 【bzoj1503】[NOI2004]郁闷的出纳员
1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 13890 Solved: 5086[Submit][Stat ...
- bzoj 3224 NOI2004郁闷的出纳员
NOI2004郁闷的出纳员 2013年12月26日6,1818 输入描述 Input Description 第一行有两个非负整数n和min.n表示下面有多少条命令,min表示工资下界. 接下来的n行 ...
- bzoj1503: [NOI2004]郁闷的出纳员(伸展树)
1503: [NOI2004]郁闷的出纳员 题目:传送门 题解: 修改操作一共不超过100 直接暴力在伸展树上修改 代码: #include<cstdio> #include<cst ...
- BZOJ 1503: [NOI2004]郁闷的出纳员
1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 10526 Solved: 3685[Submit][Stat ...
- bzoj 1503: [NOI2004]郁闷的出纳员 Treap
1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 6263 Solved: 2190[Submit][Statu ...
- bzoj1503 [NOI2004]郁闷的出纳员(名次树+懒惰标记)
1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 8705 Solved: 3027[Submit][Statu ...
- BZOJ_1503_[NOI2004]郁闷的出纳员_权值线段树
BZOJ_1503_[NOI2004]郁闷的出纳员_权值线段树 Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的 工资. ...
随机推荐
- Ant Design中getFieldDecorator方法的特殊用法(小bug)
记录Ant Design中getFieldDecorator方法的特殊的一个用法 了解Ant Design表单的小伙伴都知道,getFieldDecorator在大部分情况下是用来绑定一个控件的,即像 ...
- Java防锁屏小程序
为防止系统桌面自动锁屏,只需打成jar包,写个批处理程序start.bat,双击执行保持dos窗口执行即可,无其他影响. 程序设计为每30秒动一次鼠标,可根据需要调整. 附代码: package ma ...
- [Windows] 系统清理与优化神器Advanced SystemCare 13 PRO非破解附正版激活码
Advanced SystemCare是一款功能强大的系统清理优化软件,该软件提供的主要功能有:启动项优化.注册表整理和清理.隐私清扫.垃圾文件清理.快捷方式修复.恶意软件清除.网络加速.系统优化.安 ...
- SharePoint REST 上传文件请求403错误
最近,需要在SharePoint上传文件到文档库,但是,上传的过程报错了. 错误代码 { "error": { "code": "-213057525 ...
- 深入理解 Java 并发锁
本文以及示例源码已归档在 javacore 一.并发锁简介 确保线程安全最常见的做法是利用锁机制(Lock.sychronized)来对共享数据做互斥同步,这样在同一个时刻,只有一个线程可以执行某个方 ...
- qiniuLive 连麦流程介绍
本文出自APICloud官方论坛 qiniuLive 封装了七牛直播云服务平台的移动端开放 SDK.该模块包括视频流采集和视频流播放两部分 iOS连麦流程图: Android连麦流程图: 以下部分代码 ...
- idea 忽略不需要提交的文件
1.打开git bash界面,进入到某个项目的根目录,执行下面命令 touch .gitignore 此时,再该项目的根目录里,会创建.gitignore文本,打开该文本,编辑需要忽略的文件(编辑规则 ...
- 前端.解决form-contral总是换行问题
form-control 总是会换行,后面加单位的时候很难看,如下图. <div class="col-sm-3"> <input id="invest ...
- 【java面试】IO流
一.IO 1.IO概念 ·输入流:把能够读取一个字节序列的对象称为输入流(百度百科) ·输出流:把能够写一个字节序列的对象称为输出流(百度百科) 从定义上看可能会让你感到困惑,这里解释一下:]; ...
- 重写ThreadFactory方法和拒绝策略
最近项目中要用到多线程处理任务,自然就用到了ThreadPoolTaskExecutor这个对象,这个是spring对于Java的concurrent包下的ThreadPoolExecutor类的封装 ...