P1486 [NOI2004] 郁闷的出纳员
P1486 [NOI2004] 郁闷的出纳员
郁闷的到底是出纳员还是我???
[NOI2004] 郁闷的出纳员
题目描述
输入格式
第一行有两个整数 \(n\) 和 \(\min\)。\(n\) 表示下面有多少条命令,\(\min\) 表示工资下界。
接下来的 \(n\) 行,每行一个字符 \(x\) 和一个整数 \(k\),表示一条命令。命令可以是以下四种之一:
I k新建一个工资档案,初始工资为 \(k\)。如果某员工的初始工资低于工资下界,他将立刻离开公司。A k把每位员工的工资加上 \(k\)。S k把每位员工的工资扣除 \(k\)。F k查询第 \(k\) 多的工资。
在初始时,可以认为公司里一个员工也没有。
输出格式
对于每条 F 命令,你的程序要输出一行,仅包含一个整数,为当前工资第 \(k\) 多的员工所拿的工资数,如果 \(k\) 大于目前员工的数目,则输出 \(-1\)。
输出的最后一行包含一个整数,为离开公司的员工的总数。
请注意,初始工资低于工资下界的员工不算做离开公司的员工。
数据规模与约定
对于全部的测试点,保证:
I命令的条数不超过 \(10^5\);A和S命令的总条数不超过 \(100\);F命令的条数不超过 \(10^5\);- 每次工资调整的调整量不超过 \(10^3\);
- 新员工的工资不超过 \(10^5\)。
- \(0 \leq n \leq 3 \times 10^5\),\(0 \leq \text{min} \leq 10^9\),输入的所有数字均在 \(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;
}

浙公网安备 33010602011771号