这道题用很多数据结构都可以做,这里用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; }