bzoj1503 郁闷的出纳员(平衡树,思维)
Posted yimmortal
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1503 郁闷的出纳员(平衡树,思维)相关的知识,希望对你有一定的参考价值。
题目大意:
现在有n个操作和一个最低限度m
(I)命令(I k)新建一个工资档案,初始工资为k。
(A)命令$A k $把每位员工的工资加上k
(S)命令$S k $把每位员工的工资扣除k
(F)命令$ F k(查询第k多的工资 (如果当前的员工总数不够k,就输出)-1$)
其中(n le 100000)
最后还要输出最终离开了多少个员工
需要注意的是 ,如果某员工的初始工资低于工资下界,他将立刻离开公司!!!!
一看这个题,就感觉是个(splay)了
不过emmmm 这个整体加和整体减应该怎么弄呢
我们考虑维护一个整体的变化值(tmp)
那么对于splay中的每个元素,它的实际权值就是(x+tmp)
这么来说
对于(I)操作,如果它的权值(>)m,则(insert(x-tmp))
对于(A)操作,直接(tmp+=x)
对于(S)操作,我们让(tmp-=x),并且判断有没有需要退出的点(就是直接将(-inf)转到(root),然后把(min1-tmp-1)的后继转到root的右儿子,删掉左儿子)这样做的原因是避免哨兵被删掉
对于(F)操作,那就直接返回第k大,然后(+tmp)就可以
代码还是有很多细节的,比如要维护当前平衡树中有几个元素,事先加入哨兵之类的,直接看代码吧
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch==‘-‘) f=-1;ch=getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
return x*f;
}
const int maxn = 1e6+1e2;
int ch[maxn][4];
int val[maxn],sz[maxn],size;
int fa[maxn];
int cnt[maxn];
int n,m,ymh,root,min1;
int tot;
int num=0;
int ans;
int son(int x)
{
if (x==ch[fa[x]][0]) return 0;
else return 1;
}
void update(int x)
{
sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];
}
void rotate(int x)
{
int y=fa[x],z=fa[y];
int b=son(x),c=son(y);
ch[z][c]=x;
fa[x]=z;
ch[y][b]=ch[x][!b];
fa[ch[x][!b]]=y;
ch[x][!b]=y;
fa[y]=x;
update(y);
update(x);
}
void splay(int x,int p)
{
while (fa[x]!=p)
{
int y=fa[x],z=fa[y];
if (z==p) rotate(x);
else
{
if (son(x)==son(y))
{
rotate(y);
rotate(x);
}
else
{
rotate(x);
rotate(x);
}
}
}
if (fa[x]==0) root=x;
}
int find_qq(int x)
{
int now = root,num=0;
while (now)
{
if (val[now]<x)
{
num=now;
now=ch[now][1];
}
else now=ch[now][0];
}
return num;
}
int find_hj(int x)
{
int now = root,num=0;
while (now)
{
if (val[now]>x)
{
num=now;
now=ch[now][0];
}
else now=ch[now][1];
}
return num;
}
void insert(int x)
{
tot++;
int qq = find_qq(x);
int hj = find_hj(x);
splay(qq,0);
splay(hj,qq);
int y = ch[hj][0];
if (cnt[y])
{
cnt[y]++;
update(y);
}
else
{
++size;
ch[hj][0]=size;
fa[size]=hj;
val[size]=x;
cnt[size]=1;
sz[size]=1;
//cout<<"gg11"<<endl;
update(size);
}
}
void delet(int x)
{
--tot;
int qq = find_qq(x);
int hj = find_hj(x);
splay(qq,0);
splay(hj,qq);
int y = ch[hj][0];
if (cnt[y]>1)
{
cnt[y]--;
update(y);
}
else
{
cnt[y]=0;
fa[y]=0;
ch[hj][0]=0;
sz[y]=0;
val[y]=0;
}
}
int kth(int x)
{
int now = root;
while (1)
{
if (x<=sz[ch[now][0]]) now=ch[now][0];
else{
if (x<=sz[ch[now][0]]+cnt[now]) return val[now];
x-=sz[ch[now][0]]+cnt[now];
now=ch[now][1];
}
}
}
int add;
int main()
{
size=2;
val[1]=2e9;
val[2]=-2e9;
fa[2]=1;
ch[1][0]=2;
root=1;
scanf("%d%d",&n,&min1);
for (int i=1;i<=n;i++)
{
char s[10];
int x;
scanf("%s",s+1);
//cout<<size<<endl;
x=read();
//cout<<x<<endl;
if (s[1]==‘A‘)
{
ymh+=x;
}
if (s[1]==‘S‘)
{
ymh-=x;
int hj = find_hj(min1-ymh-1);
splay(2,0);
splay(hj,2);
int pos = ch[hj][0];
ans+=sz[pos];
tot-=sz[pos];
fa[pos]=0;
ch[hj][0]=0;
sz[pos]=0;
cnt[pos]=0;
/*if (tot==0)
{
size=2;
val[1]=2e9;
val[2]=-2e9;
fa[2]=1;
ch[1][0]=2;
root=1;
}*/
//cout<<ans;
}
if (s[1]==‘I‘)
{
if (x<min1) continue;
//cout<<"gg"<<endl;
insert(x-ymh);
}
if (s[1]==‘F‘)
{
//cout<<tot<<endl;
if (x>tot)
printf("-1
");
else
printf("%d
",kth(tot-x+1)+ymh);
}
//cout<<tot<<endl;
}
cout<<ans;
return 0;
}
以上是关于bzoj1503 郁闷的出纳员(平衡树,思维)的主要内容,如果未能解决你的问题,请参考以下文章