这道题用很多数据结构都可以做,这里用splay实现。
因为增加工资和减少工资都是对所有员工进行操作,所以维护一个delta就行,因为操作只对之前的工资档案有效,所以在新加入数据时需先减去delta。
还有就是如果刚来就低于下界的人是不计入离开的总人数的。
splay维护子树的size以及每个数据的个数cnt,其他就是基本的操作。
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100000 + 10;
int delta = 0,ans = 0;
int size = 0,root = 0;
int n,min_cost;
struct SplayTree
{
int data[maxn];
int cnt[maxn];
int ch[maxn][2],t_size[maxn][2];
int pre[maxn];
inline int min(int a,int b)
{
return a < b ? a : b;
}
inline void rotate(int x,int f)
{
int y = pre[x],z = pre[y];
ch[y][!f]= ch[x][f];
t_size[y][!f] = t_size[x][f];
pre[ ch[x][f] ] = y;
ch[x][f] = y;
t_size[x][f] = t_size[y][0] + t_size[y][1] + cnt[y];
pre[y] = x;
pre[x] = z;
if(z)
{
ch[z][ch[z][1] == y] = x;
t_size[z][ch[z][1] == x] = t_size[x][0] + t_size[x][1] + cnt[x];
}
}
void splay(int x)
{
int y,z;
while(pre[x] != 0)
{
y = pre[x],z = pre[y];
if(z == 0)
{
if(x == ch[y][0])rotate(x,1);
else rotate(x,0);
break;
}
if(x == ch[y][0])
{
if(y == ch[z][0])rotate(y,1),rotate(x,1);
else rotate(x,1),rotate(x,0);
}
else
{
if(y == ch[z][1])rotate(y,0),rotate(x,0);
else rotate(x,0),rotate(x,1);
}
}
root = x;
}
void insert(int x)
{
data[++size] = x;
cnt[size] = 1;
if(root == 0)
{
root = size;
return;
}
int pos = root,tmp;
while(pos != 0)
{
tmp = pos;
if(x == data[tmp])
{
cnt[tmp]++;
splay(tmp);
return;
}
if(x < data[tmp])pos = ch[pos][0];
else pos = ch[pos][1];
}
pre[size] = tmp;
if(x <= data[tmp])ch[tmp][0] = size;
else ch[tmp][1] = size;
splay(size);
}
void del()
{
int p = root,tmp = -1;
while(p != 0)
{
if(data[p] + delta < min_cost)tmp = p,p = ch[p][1];
else p = ch[p][0];
}
if(tmp == -1)return;
p = tmp;
splay(p);
ans += t_size[p][0] + cnt[p];
root = ch[p][1];
if(root != 0)pre[root] = 0;
}
int query(int k,int p)
{
if(t_size[p][1] < k && t_size[p][1] + cnt[p] >= k)return data[p];
if(t_size[p][1] >= k)return query(k,ch[p][1]);
else return query(k - t_size[p][1] - cnt[p],ch[p][0]);
}
}Spt;
void init()
{
freopen("bzoj1503.in","r",stdin);
freopen("bzoj1503.out","w",stdout);
}
void readdata()
{
scanf("%d%d",&n,&min_cost);
}
void solve()
{
for(int i = 1;i <= n;i++)
{
char op[2];
int p;
scanf("%s%d",op,&p);
if(op[0] == 'I')
{
if(p >= min_cost)
{
p -= delta;
Spt.insert(p);
}
}
if(op[0] == 'A')delta += p;
if(op[0] == 'S')
{
delta -= p;
Spt.del();
}
if(op[0] == 'F')
{
if(p > Spt.t_size[root][0] + Spt.t_size[root][1] + Spt.cnt[root])printf("-1\n");
else printf("%d\n",Spt.query(p,root) + delta);
}
}
printf("%d",ans);
}
int main()
{
init();
readdata();
solve();
return 0;
}
然后另一个是使用SBT实现的,总的来说SBT比splay实现的平衡树效率要高很多。
代码:
#include<cstdio>
#include<cstring>
#define L ch[p][0]
#define R ch[p][1]
#define LL ch[ch[p][0]][0]
#define RR ch[ch[p][1]][1]
#define LR ch[ch[p][0]][1]
#define RL ch[ch[p][1]][0]
using namespace std;
const int maxn = 200000;
int ch[maxn][2];
int sz[maxn],val[maxn];
int n,min,root;
int top = 0,delta = 0;
int ans = 0;
void init()
{
freopen("cashier.in","r",stdin);
freopen("cashier.out","w",stdout);
}
void Rotate(int &p,int f)
{
int k = ch[p][!f];
ch[p][!f] = ch[k][f];
ch[k][f] = p;
sz[k] = sz[p];
sz[p] = sz[L] + sz[R] + 1;
p = k;
}
void maintain(int &p,bool flag)
{
if(p == 0)return;
if(!flag)
{
if(sz[LL] > sz[R])Rotate(p,1);
else if(sz[LR] > sz[R])Rotate(L,0),Rotate(p,1);
else return;
}
else
{
if(sz[RR] > sz[L])Rotate(p,0);
else if(sz[RL] > sz[L])Rotate(R,1),Rotate(p,0);
else return;
}
maintain(L,false);
maintain(R,true);
maintain(p,false);
maintain(p,true);
}
void insert(int &p,int key)
{
if(p == 0)
{
p = ++top;
ch[p][0] = ch[p][1] = 0;
sz[p] = 1;
val[p] = key;
return;
}
sz[p]++;
if(key < val[p])insert(ch[p][0],key);
else insert(ch[p][1],key);
maintain(p,!(key < val[p]));
}
void del(int &p)
{
if(!p)return;
if(val[p] + delta < min)p = ch[p][1],del(p);
else del(ch[p][0]),sz[p] = sz[ ch[p][0] ] + sz[ ch[p][1] ] + 1;
}
int find(int &p,int k)
{
if(sz[ ch[p][1] ] >= k)return find(ch[p][1],k);
else if(sz[ ch[p][1] ] + 1 == k)return val[p];
else return find(ch[p][0],k - sz[ ch[p][1] ] - 1);
}
void readdata()
{
scanf("%d%d",&n,&min);
int tot = 0;
for(int i = 1;i <= n;i++)
{
char op[2];
int tmp;
scanf("%s%d",op,&tmp);
if(op[0] == 'I')
{
if(tmp >= min)insert(root,tmp - delta),tot++;
}
if(op[0] == 'A')delta += tmp;
if(op[0] == 'S')
{
delta -= tmp;
del(root);
}
if(op[0] == 'F')
{
if(sz[root] < tmp)printf("-1\n");
else printf("%d\n",find(root,tmp) + delta);
}
}
printf("%d\n",tot - sz[root]);
}
int main()
{
init();
readdata();
return 0;
}