bzoj1503 [ NOI2004 ] --treap
这道题和一般的题目不同,A和S操作要修改所有节点。所以定义基准d,每个节点的工资是它的值+d,这样就能完成所有操作。
I k:将值为k-d的节点插入treap
A k:将d加上k
S k:将d减去k,并将所有值小于min-d的节点删除。
F k:因为treap在插入时就是有序的,所以直接查找。
这里要注意:
在实际编码中,为了减少出错的可能性,一般用一个真实的指针null代替空指针NULL,方法如下:
Node *null=new Node();
还有一个略坑的地方就是如果一个员工的初始工资低于工资下界,他将立即离开公司。这不算在离开公司的员工总数内。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; struct Node{ int v,r,s; Node* ch[2]; int cmp(int x)const{ if(x==v)return -1; return x>v?1:0; } void push_up(){ s=ch[0]->s+ch[1]->s+1; } }; Node* null=new Node(); Node* root=null; int i,j,k,n,m,x,y,tot,d,sum; char c[1]; void rotate(Node* &o,int d){ Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o; o->push_up(); k->push_up(); o=k; } void insert(Node* &o,int x){ if(o==null){ o=new Node(); o->ch[0]=o->ch[1]=null; o->v=x; o->r=rand(); o->s=1; }else{ int d=o->v>x?0:1; insert(o->ch[d],x); if(o->ch[d]->r>o->r)rotate(o,d^1); } o->push_up(); } int del(Node* &o,int x){ if(o==null)return 0; if(o->v<x){ int t=o->ch[0]->s+1; o=o->ch[1]; return t+del(o,x); }else{ int t=del(o->ch[0],x); o->s-=t; return t; } } int find(Node* o,int x){ int s=o->ch[1]==null?0:o->ch[1]->s; if(s+1==x)return o->v; if(s>=x)return find(o->ch[1],x); return find(o->ch[0],x-s-1); } int main() { scanf("%d%d",&n,&m); d=tot=0; for(i=1;i<=n;i++){ scanf("%s%d",c,&x); if(c[0]=='I')if(x>=m)insert(root,x-d); if(c[0]=='A')d+=x;else if(c[0]=='S'){ d-=x; tot+=del(root,m-d); }else if(c[0]=='F')if(x>root->s)printf("-1\n");else printf("%d\n",find(root,x)+d); } printf("%d\n",tot); return 0; }