这是一道练手的水题啦!写网络流怕把splay忘了,于是来练习一下splay。这是一道很经典的splay入门题,用size域查询排名,维护的仍然是有序表,只是由于涉及到删除插入的操作,包括询问排名,所以线段树不是很好实现(但事实上是可以的)。
尽管是道很基础的题,但是还是有很多地方值得注意:
1、由于员工工资可能是一样的,所以如果让重复的元素出现在树中,则会使删除操作变得异常麻烦。于是我们应该添加一个num域表示当前元素在树中出现的个数。那么有两个操作将被修改:
(1). 在进行update更新时,函数应变成
this->size=l->size+r->size+this->num;
(2). 查找第k大的元素也应该修改,具体看代码
2、在进行删除操作时,千万不能删多了,这个有一些写法上的技巧。
3、splay的关键地方必须及时更新,否则可能会出现奇怪的错误。
4、这个题目的大坑点,如果某员工开始时工资低于最低工资标准,那么他不用算在离开的人数内(出题人语文没学好O__O"…)。
#include <cstdio>
#define __add(x,w) lazy[x]+=w,a[x]+=w
#define update(x) if((x)) s[x]=s[l[x]]+s[r[x]]+num[x]
#define MaxN 100010
using namespace std;
int a[MaxN],l[MaxN],r[MaxN],num[MaxN],s[MaxN],lazy[MaxN];
int n,low,t,tot,ans;
inline void push(const int &x)
{
if(!x) return;
__add(l[x],lazy[x]);
__add(r[x],lazy[x]);
lazy[x]=0;
}
inline void zig(int &x)
{
int lc=l[x];
l[x]=r[lc];
r[lc]=x;
update(x);
x=lc;
}
inline void zag(int &x)
{
int rc=r[x];
r[x]=l[rc];
l[rc]=x;
update(x);
x=rc;
}
inline void splay(int &t,int x)
{
if(!t) return;
int p,pl=0,pr=0,last;
for(;;)
{
push(t);
push(l[t]);
push(r[t]);
if(x==a[t]) break;
if(x<a[t]&&!l[t]) break;
if(x>a[t]&&!r[t]) break;
if(x<a[t])
{
if(x<a[l[t]]&&l[l[t]]) zig(t);
p=l[t],l[t]=pr,pr=t,t=p;
}
else
{
if(x>a[r[t]]&&r[r[t]]) zag(t);
p=r[t],r[t]=pl,pl=t,t=p;
}
}
last=l[t];
while(pl)
{
p=r[pl],r[pl]=last;
update(pl);
last=pl,pl=p;
}
l[t]=last;
last=r[t];
while(pr)
{
p=l[pr],l[pr]=last;
update(pr);
last=pr,pr=p;
}
r[t]=last;
update(t);
}
inline void insert(const int &x)
{
if(x<low) return;
splay(t,x);
if(!t) a[++tot]=x,t=tot;
if(x==a[t])
{
num[t]++;
update(t);
}
else
{
a[++tot]=x;
num[tot]++;
if(x<a[t])
l[tot]=l[t],
l[t]=tot;
else
r[tot]=r[t],
r[t]=tot;
update(tot);
update(t);
}
}
inline void cheak()
{
splay(t,low);
if(a[t]<low) splay(r[t],a[t]),zag(t);
ans+=s[l[t]];
l[t]=0;
update(t);
}
inline int ask(int &x)
{
if(x>s[t]) return -1;
int temp=t,cmp;
for(;;)
{
push(temp);
push(l[temp]);
push(r[temp]);
cmp=s[r[temp]]+num[temp];
if(x<=cmp&&x>s[r[temp]])
return a[temp];
else if(x<=s[r[temp]])
temp=r[temp];
else
x-=cmp,
temp=l[temp];
}
}
int main()
{
//freopen("in","r",stdin);
//freopen("out","w",stdout);
char s[2];int x;
scanf("%d%d",&n,&low);
while(n--)
{
scanf("%s%d",s,&x);
if(s[0]=='I')
insert(x);
else if(s[0]=='A')
__add(t,x);
else if(s[0]=='S')
__add(t,-x),
cheak();
else printf("%d\n",ask(x));
}
printf("%d",ans);
return 0;
}