P1486 [NOI2004] 郁闷的出纳员

P1486 [NOI2004] 郁闷的出纳员

郁闷的到底是出纳员还是我???

[NOI2004] 郁闷的出纳员

题目描述

输入格式

第一行有两个整数 nminn 表示下面有多少条命令,min 表示工资下界。

接下来的 n 行,每行一个字符 x 和一个整数 k,表示一条命令。命令可以是以下四种之一:

  • I k 新建一个工资档案,初始工资为 k。如果某员工的初始工资低于工资下界,他将立刻离开公司。
  • A k 把每位员工的工资加上 k
  • S k 把每位员工的工资扣除 k
  • F k 查询第 k 多的工资。

在初始时,可以认为公司里一个员工也没有。

输出格式

对于每条 F 命令,你的程序要输出一行,仅包含一个整数,为当前工资第 k 多的员工所拿的工资数,如果 k 大于目前员工的数目,则输出 1

输出的最后一行包含一个整数,为离开公司的员工的总数。

请注意,初始工资低于工资下界的员工不算做离开公司的员工。

数据规模与约定

对于全部的测试点,保证:

  • I 命令的条数不超过 105
  • AS 命令的总条数不超过 100
  • F 命令的条数不超过 105
  • 每次工资调整的调整量不超过 103
  • 新员工的工资不超过 105
  • 0n3×1050min109,输入的所有数字均在 32 位带符号整形范围内。

solution:

平衡树练手题,我们维护一颗平衡树。
观察到A和S的命令数十分的少,我们对于每次命令S:
直接把减掉k后不符合条件的点删掉
用FHQ-Treap十分好写就是了

然后对于每次A和S,对应剩下的节点dfs一下来更新权值(由于操作次数少,基本不用担心超时)

然后对于每次查询,直接平衡树基本操作,这里不多赘述

但是这里主要说一些细节:

split(rt,mi-tag,a,b)

我们在每次执行S时,val<mi-tag的都要被切掉(之前写成<mi-tag-1)调了好久

还有就是读懂题目:

if(c=='I'&&x>=mi){insert(rt,x);}

如果他刚开始工资就少,那他必然是不干的

还有一个神仙细节是我写的FHQ-Treap貌似不能直接分裂出一个空树,所以当被割完之后的rt只有一个节点且其权值小于mi-tag时,将它重置然后将rt记为0:

if(t[rt].val<mi-tag&&t[rt].siz==1)
{
t[rt]={0,0,0,0,0};
rt=0;
}
tag=0;

然后这题基本就做完了

Code:

#include<bits/stdc++.h>
#include<ctime>
const int N=3e5+5;
using namespace std;
int n,m,mi,cnt,rt,tag,ans;
struct Tree{
int val,pri,siz,ls,rs;
}t[N<<2];
int new_(int val=0)
{
t[++cnt]={val,rand(),1,0,0};
return cnt;
}
void pushup(int x)
{
t[x].siz=t[t[x].ls].siz+t[t[x].rs].siz+1;
}
void split(int x,int k,int &l,int &r)
{
if(!x){l=r=0;return ;}
if(k<=t[x].val)//in ls
{
r=x;
split(t[x].ls,k,l,t[r].ls);
pushup(r);
}
else//in rs
{
l=x;
split(t[x].rs,k,t[l].rs,r);
pushup(l);
}
}
int merge(int x,int y)
{
if(!x||!y)return x+y;
if(t[x].pri<t[y].pri)
{
t[x].rs=merge(t[x].rs,y);
pushup(x);
return x;
}
else
{
t[y].ls=merge(x,t[y].ls);
pushup(y);
return y;
}
}
int query_kth(int x,int k)
{
if(k==t[t[x].ls].siz+1)return t[x].val;
if(k<=t[t[x].ls].siz)return query_kth(t[x].ls,k);
return query_kth(t[x].rs,k-(t[t[x].ls].siz+1));
}
void dfs(int x,int k)
{
if(!x)return ;
t[x].val+=k;
dfs(t[x].ls,k);dfs(t[x].rs,k);
pushup(x);
}
void upd_val(int &rt,int k)//-=k
{
if(k<0)
{
tag+=k;
int a=0,b=0;//val+tag<mi :val<mi-tag
split(rt,mi-tag,a,b);//a[1,k-1] : b[k,inf]
rt=b;
ans+=t[a].siz;
dfs(rt,tag);
pushup(rt);
if(t[rt].val<mi-tag&&t[rt].siz==1)
{
t[rt]={0,0,0,0,0};
rt=0;
}
tag=0;
}
else
{
tag+=k;
dfs(rt,tag);
pushup(rt);
tag=0;
}
}
void insert(int &rt,int k)
{
int a=0,b=0;
split(rt,k,a,b);//a[1,k] : b[k+1,inf]
rt=merge(merge(a,new_(k)),b);
pushup(rt);
}
void work()
{
cin>>n>>mi;
char c;
int x;
for(int i=1;i<=n;i++)
{
std::cin>>c>>x;
if(c=='I'&&x>=mi){insert(rt,x);}
if(c=='A'){upd_val(rt,x);}
if(c=='S'){upd_val(rt,-x);}
if(c=='F')
{
int k=t[rt].siz-x+1;
printf("%d\n", k>0? query_kth(rt,k) : -1);
}
}
printf("%d",cnt-t[rt].siz);
}
int main()
{
//freopen("P1486_3.in","r",stdin);//freopen("P1486.out","w",stdout);
srand(clock());
work();
return 0;
}
posted @   liuboom  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示