P1486 [NOI2004] 郁闷的出纳员

题目链接:P1486 [NOI2004] 郁闷的出纳员

题意:维护一个数据结构,支持

  1. 插入一个大小为 kkk​ 的值,小于下界时不插入
  2. 所有元素加上 kkk
  3. 所有元素减去 kkk ,小于下界的删除
  4. 查询所有元素中的 kkk​ 大值

最后输出删除的元素个数(两元素相等算两个)

可以用平衡树来解决本题

听说正解是splay,不过我来讲一种替罪羊树的写法

我们可以维护一个 ddd​ ,表示每次加减的变化

这样每个元素就可以用 x+dx+dx+d 的形式表示了

在平衡树里放原来的数减去插入时的 ddd ,即 k−dk-dk−d

这样输出的时候就是正常的数了

那小于下界的怎么搞呢?

根据替罪羊树的性质,我们可以直接把整课树重构

Flatten操作时判断当前元素 xxx 加上 ddd​ 是否超过下界,且存在,否则就直接不管它了

kkk​ 大值直接查 num1−k+1num1-k+1num1−k+1​ 小值就好了

这个 num1num1num1 表示每次操作后的剩余结点数(两元素相等算两个)

因为它最后还有个询问删除的,再记录一下总插入结点数(两元素相等算两个) num2num2num2​ ,答案就是 num2−num1num2-num1num2−num1

这样整个算法的时间复杂度为 O(nlog⁡n)O(n\log n)O(nlogn)​

本题在luogu上的数据是windows下造的,所以还要注意换行符是\r\n,不是linux下的\n

代码如下

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define MAXN (int)(3e5+5)
#define gc() getchar()
#define pc(a) putchar(a)
template<typename T>inline void read(T &k)
{char ch=gc();T x=0,f=1;while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}k=x*f;
}
template<typename T>inline void write(T k)
{if(k<0){k=-k;pc('-');}if(k>9)write(k/10);pc(k%10+'0');
}
namespace BT
{#define ls(at) a[at].l#define rs(at) a[at].rint n,m;int d,num1,num2;struct node{int l,r,num,cnt,s,sz,sd;}a[MAXN];double alpha=0.75;int tot,rt;int tmp[MAXN];int New(int x){a[++tot]={0,0,x,1,1,1,1};return tot;}void push_up(int at){a[at].s=a[ls(at)].s+a[rs(at)].s+1;a[at].sz=a[ls(at)].sz+a[rs(at)].sz+a[at].cnt;a[at].sd=a[ls(at)].sd+a[rs(at)].sd+(a[at].cnt!=0);}bool CanR(int at){double x=a[at].s*alpha;return a[at].cnt&&(x<=(double)max(a[ls(at)].s,a[rs(at)].s)||(double)a[at].sd<=x);}void CanR_flatten(int &idx,int at){if(!at)return;CanR_flatten(idx,ls(at));if(a[at].cnt){if(a[at].num+d>=m)tmp[++idx]=at; //在这里就筛掉不满足下界的else num1-=a[at].cnt; // 注意不是减1,因为可能有相同的元素}CanR_flatten(idx,rs(at));}int CanR_build(int l,int r){if(l>=r)return 0;int mid=(l+r)>>1;int &at=tmp[mid];ls(at)=CanR_build(l,mid);rs(at)=CanR_build(mid+1,r);push_up(at);return at;}void rebuild(int &at){int idx=0;CanR_flatten(idx,at);at=CanR_build(1,idx+1);}void insert(int x,int &at){if(!at){at=New(x);return;}if(a[at].num==x)++a[at].cnt;else if(x<a[at].num)insert(x,ls(at));else insert(x,rs(at));push_up(at);if(CanR(at))rebuild(at);}void remove(int x,int &at){if(!at)return;if(x==a[at].num){if(a[at].cnt)--a[at].cnt;}else if(x<a[at].num)remove(x,ls(at));else remove(x,rs(at));push_up(at);if(CanR(at))rebuild(at);}int uprbd(int x,int at){if(!at)return 1;if(x==a[at].num&&a[at].cnt)return a[ls(at)].sz+a[at].cnt+1;else if(x<a[at].num)return uprbd(x,ls(at));else return uprbd(x,rs(at))+a[ls(at)].sz+a[at].cnt;}int uprbd_gt(int x,int at){if(!at)return 0;if(x==a[at].num&&a[at].cnt)return a[ls(at)].sz;else if(x<a[at].num)return uprbd_gt(x,ls(at));else return uprbd_gt(x,rs(at))+a[ls(at)].sz+a[at].cnt;}int getval(int x,int at){if(!at)return INF;if(x<=a[ls(at)].sz)return getval(x,ls(at));if(x<=a[ls(at)].sz+a[at].cnt)return a[at].num;else return getval(x-a[ls(at)].sz-a[at].cnt,rs(at));}int getpre(int x,int at){return getval(uprbd_gt(x,at),at);}int getnext(int x,int at){return getval(uprbd(x,at),at);}int getrank(int x,int at){return uprbd_gt(x,at)+1;}
}
signed main()
{using namespace BT; // 替罪羊树 qwqread(n);read(m);for(int i=1; i<=n; i++){char op;int x;char t;//gc(); //win下要用op=gc();read(x);if(op=='I'&&x>=m) // 不满下界的直接不管了{insert(x-d,rt);++num1;++num2;}if(op=='A')d+=x;if(op=='F'){if(num1<x)puts("-1"); // 不满k个数else {write(getval(num1-x+1,rt)+d);pc('\n');}}if(op=='S'){d-=x;rebuild(rt); // 直接重构}}write(num2-num1);pc('\n');return 0;
}

转载请说明出处

洛谷P1486 [NOI2004] 郁闷的出纳员 题解相关推荐

  1. 洛谷 P1486 [NOI2004]郁闷的出纳员

    题目描述 OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资 ...

  2. 洛谷 P1486 [NOI2004]郁闷的出纳员【Treap】

    题目描述 OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资 ...

  3. 【NOI2004】【洛谷P1486】郁闷的出纳员(Splay写法)

    传送门 平衡树简单题 因为是全局加减 维护一下全局一个addaddadd表示当前工资加减情况 删除就把最低要求的后继SplaySplaySplay到根 然后把左儿子删去就是了 因为个人代码是旋转了后继 ...

  4. 【洛谷P1486】郁闷的出纳员【树状数组】

    题目描述 题目链接 分析 听说暴力能过 ,不敢打Treap/线段树. 很巧妙的一道题,第一次听说树状数组查询第k大/小的数. 定义树状数组为工资点上的人数,对于工资的整体增减可以通过设置变量p统一维护 ...

  5. BZOJ1503:[NOI2004]郁闷的出纳员——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1503 (题面复制的洛谷的,因为洛谷好看) 题目描述 OIER公司是一家大型专业化软件公司,有着数以万 ...

  6. NOI2004郁闷的出纳员题解

    描述 OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如 ...

  7. P1486 [NOI2004]郁闷的出纳员

    题目描述 OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资 ...

  8. P1486 [NOI2004] 郁闷的出纳员 FHQ-Treap

    题意: 第一行有两个整数 nnn 和 min⁡min⁡min⁡.nnn 表示下面有多少条命令,min⁡min⁡min⁡ 表示工资下界. 接下来的 nnn 行,每行一个字符xxx和一个整数 kkk,表示 ...

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

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

最新文章

  1. Vue Router webpack
  2. 解决zabbix-agent二进制班不能连接使用docker搭建的zabbix-server
  3. 《18成长,19蜕变》
  4. C# — 创建Windows服务
  5. mysql中将某个字段做计算,mysql创建计算字段使用子查询教程
  6. sql建立到mysql的会话_SQLalchemy会话和多个数据库尝试创建twi索引
  7. 适合小白的Python学习大纲
  8. 钉钉新增“下班勿扰”功能:次日上班前不接受任何消息!
  9. [1-7] 把时间当做朋友(李笑来)Chapter 7 【从此时此刻开始改变】 摘录
  10. linux设置伪静态地址,wordpress网站linux和win主机URL伪静态设置方法详解
  11. 数学4如何用计算机画正切函数图像,7.3.4正切函数的性质和图像
  12. 程序教程基础_电脑是个啥玩意
  13. 相比于深度学习,传统的机器学习算法难道就此没落了吗,还有必要去学习吗?
  14. 亲水性小分子PEG DBCO-PEG4-酸,1416711-60-8可以进行点击化学反应
  15. CodeForces 711B. Chris and Magic Square(水题)
  16. 大学专业有C语言专业吗,大学里哪些专业开设C语言、数电、模电、单片机、嵌入式等课程?...
  17. 什么是vue-resource?
  18. h3c r4900服务器系统安装,H3C R4900 G3安装CentOS 6.7网卡配置方法
  19. 提高计算机的安全等级水平,电脑安全防护等级设置
  20. 人物照片墙html 模板,用PS制作散落照片墙效果的人物照片

热门文章

  1. Kinect开发教程一:OpenNI的安装与开发环境配置
  2. PPT动画教程:配色方案
  3. 长生生物收到深交所重大违法强制退市决定,2019首支退市股!...
  4. 1.学生版阿里云简单配置和win7、win10专业版及win10家庭版的远程桌面的配置详解
  5. G722 Series Intro
  6. 蚂蚁金服简单的几道面试题目,却坑了90%程序员!
  7. PHP的各种安全问题总结 一文了解PHP的各类漏洞和绕过姿势
  8. 『前端学习实例』 静态网页(Bootstrap)
  9. 6/7/8/9/10/11代主板刷bios跳过校验方法刷修改bios自制bios方法
  10. 安卓系统USB产品芯片使用推荐