【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;
}
View Code

 

posted @ 2017-02-08 21:28  ONION_CYC  阅读(193)  评论(0编辑  收藏  举报