【NOI】2004 郁闷的出纳员
【算法】平衡树(treap)
【题解】
treap知识见数据结构。
解法,具体细节见程序。
#include<cstdio> #include<algorithm> #include<ctime> using namespace std; const int maxn=100010; struct cyc{int l,r,rnd,s,num;}t[maxn*3]; int n,sz,low,root,delta; void rturn(int &tt) { int k=t[tt].l; t[tt].l=t[k].r; t[k].r=tt; t[k].s=t[tt].s; t[tt].s=t[t[tt].l].s+t[t[tt].r].s+1; tt=k; } void lturn(int &tt) { int k=t[tt].r; t[tt].r=t[k].l; t[k].l=tt; t[k].s=t[tt].s; t[tt].s=t[t[tt].l].s+t[t[tt].r].s+1; tt=k; } void insert(int &k,int x) { if(k==0) { k=++sz; t[k].rnd=rand(); t[k].s=1;//s表示该子树的节点个数(含本身) t[k].num=x; return; } t[k].s++; if(x<t[k].num) { insert(t[k].l,x); if(t[t[k].l].rnd<t[k].rnd)rturn(k); } else { insert(t[k].r,x); if(t[t[k].r].rnd<t[k].rnd)lturn(k); } } int del(int &k,int x) { int sum=0; if(k==0)return 0; if(x>t[k].num){sum=t[t[k].l].s+1;k=t[k].r;return sum+del(k,x);}//直接将根从k变为k的右子树,由于&的传递效果,相当于直接废了左子树和根节点,把右子树接上去。 else{sum=del(t[k].l,x);t[k].s-=sum;return sum;} } int find(int k,int x) { if(t[t[k].l].s+1==x)return(t[k].num+delta); if(x<=t[t[k].l].s)return(find(t[k].l,x)); else return(find(t[k].r,x-t[t[k].l].s-1)); } int main() { scanf("%d%d",&n,&low); srand(time(0)); int ans=0; for(int i=1;i<=n;i++) { char c=getchar();int rd; while(c<'A'||c>'Z')c=getchar(); scanf("%d",&rd); if(c=='I')if(rd>=low)insert(root,rd-delta); if(c=='A')delta+=rd; if(c=='S'){delta-=rd;ans+=del(root,low-delta);} if(c=='F') { if(t[root].s<rd)printf("-1\n"); else printf("%d\n",find(root,t[root].s-rd+1)); } } printf("%d",ans); return 0; }