\[Preface
\]

之前用 treap 打,交了四遍才过。

自学了 fhq treap 后,才意识到是一道 fhq treap 板子题,直接码上,一遍就过。

本题解提供的是 fhq treap 做法(感谢 fhq 神犇),不太了解 fhq treap 的同学可以去了解一下 fhq treap ,挺好理解的。(至少要了解两种 split 和 merge 操作)

\[Description
\]

你需要维护一个可重集,支持 \(4\) 种操作:

I k 向集合内插入元素 \(k\) 。

A k 将集合内所有元素加上 \(k\) 。

S k 将集合内所有元素减去 \(k\) 。

F k 查询集合内第 \(k\) 大。

一共 \(n\) 次操作。

一开始给出一个下界 \(Minv\) ,表示集合内的所有元素必须大于等于 \(Minv\) ,在任何时刻,小于 \(Minv\) 的所有元素会被立刻删除。

最后还要输出被删除的元素个数。

\[Solution
\]

对于 I k 操作:

​ 首先先判断一下 \(k\) 是否大于等于 \(Minv\) ,之后就是经典的插入操作了。

​ 让原树按 \(k-1\) 分裂成两棵树 \(x,y\) ,新建值为 \(k\) 的节点 \(New\) ,合并 \(x,New,y\) 。

\(~\)

对于 A kS k 操作:

​ 考虑到 " AS 命令的总条数不超过 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 大也是可以的。

\(~\)

至此,此题得到完美解决。

\[Code
\]

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

\[Thanks \ for \ watching
\]

题解 NOI2004【郁闷的出纳员】的更多相关文章

  1. [BZOJ1503][NOI2004]郁闷的出纳员

    [BZOJ1503][NOI2004]郁闷的出纳员 试题描述 OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是 ...

  2. BZOJ 1503: [NOI2004]郁闷的出纳员 splay

    1503: [NOI2004]郁闷的出纳员 Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作 ...

  3. [BZOJ1503][NOI2004]郁闷的出纳员 无旋Treap

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MB Description OIER公司是一家大型专业化软件公司,有着数以万计的员 ...

  4. 【bzoj1503】[NOI2004]郁闷的出纳员

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 13890  Solved: 5086[Submit][Stat ...

  5. bzoj 3224 NOI2004郁闷的出纳员

    NOI2004郁闷的出纳员 2013年12月26日6,1818 输入描述 Input Description 第一行有两个非负整数n和min.n表示下面有多少条命令,min表示工资下界. 接下来的n行 ...

  6. bzoj1503: [NOI2004]郁闷的出纳员(伸展树)

    1503: [NOI2004]郁闷的出纳员 题目:传送门 题解: 修改操作一共不超过100 直接暴力在伸展树上修改 代码: #include<cstdio> #include<cst ...

  7. BZOJ 1503: [NOI2004]郁闷的出纳员

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 10526  Solved: 3685[Submit][Stat ...

  8. bzoj 1503: [NOI2004]郁闷的出纳员 Treap

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 6263  Solved: 2190[Submit][Statu ...

  9. bzoj1503 [NOI2004]郁闷的出纳员(名次树+懒惰标记)

    1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 8705  Solved: 3027[Submit][Statu ...

  10. BZOJ_1503_[NOI2004]郁闷的出纳员_权值线段树

    BZOJ_1503_[NOI2004]郁闷的出纳员_权值线段树 Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的 工资. ...

随机推荐

  1. 【原创】快速失败机制&失败安全机制

    这是why技术的第29篇原创文章 之前在写<这道Java基础题真的有坑!我求求你,认真思考后再回答.>这篇文章时,我在8.1小节提到了快速失败和失败安全机制. 但是我发现当我搜索" ...

  2. 对Java中可变参数的理解

    说明 可变参数:是DK1.5之后出现的新特性,其实可变参数是0.1.2.3.....个参数的数组 使用前提 当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数 使用格式 修饰符 ...

  3. Linux 编程题

    1. 产生一个进程树,父进程有2个子进程,这2个子进程分别又有2个子进程,每个进程休眠5秒后退出,并在退出前打印自己的进程id号. # include<stdio.h> # include ...

  4. Unity3D游戏开发培训

    Unity3D游戏开发培训 作者:Jesai 时间:2017-01-08 修改:2017-01-09 12:36:15 1         项目的构成 图1-1 如图1-1所示,Unity3D的项目构 ...

  5. 异数OS TCP协议栈测试(三)--长连接篇

    异数OS TCP协议栈测试(三)--长连接篇 本文来自异数OS社区 github:   异数OS-织梦师(消息中间件)群: 476260389 异数OS TCP长连接技术简介 说起长连接,则首先要谈对 ...

  6. [bzoj3991] [洛谷P3320] [SDOI2015] 寻宝游戏

    Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有 \(N\) 个村庄和 \(N-1\) 条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬 ...

  7. Qt Installer Framework翻译(7-2)

    包文件夹 安装程序包含的组件,要么是内嵌的,要么可以从远程存储库加载.在这两种情况下,都需要为组件使用一种安装程序可以读取的文件格式和结构. 包文件夹结构 将所有组件放在相同的根文件夹中,即包文件夹. ...

  8. Shell命令整理

    Shell命令 一.认识Shell 在Linux系统中,Shell充当着用户与Linux内核的桥梁,俗称壳保护着Linux内核,同时也负责完成用户与内核之间的交互. 当用户需要与内核交互时,将命令传递 ...

  9. python实例:从excel读取股票代码,爬取股票信息写到代码后面的单元格中

    关键词:爬虫.python.request.接口.excel处理 思路: 1.首先准备好excel文档,把股票代码事先编辑进去. 2.脚本读取文档,依次读出股票代码到指定站点发起请求获取股票信息 3. ...

  10. [校内训练20_01_20]ABC

    1.问有多少个大小为N的无标号无根树,直径恰好为L.$N,L \leq 200$ 2.问一个竞赛图中有多少个长度为3.4.5的环.$N \leq 2000$ 3.给出一些直线和单个点A,问这些直线的交 ...