您的位置:首页 > 其它

1503: [NOI2004]郁闷的出纳员

2017-07-18 18:18 260 查看
题目链接

题目大意:给出一个数列(初始为空),给出一个最小值Min,当数列中的数字小于Min时自动删除。四种操作:(1)数列中增加一个元素,设置初始值x;若x小于Min则不插入;(2)所有的元素增加一个值det;(3)所有的元素减小一个值det;此时有可能有一些会被删除(4)询问目前所有元素中第K大的。最后输出删除了多少个。

题解:因为增加减少的操作是对于所有元素的,用一个全局标记tmp记录。

每插入一个元素x,插入x-tmp,这样保证了插入元素的所有真实值都是其节点的值加上tmp

题目中要找第k大,可以维护从大到小的平衡树,也可以转化成第num-k+1小的来做

PS:开始时工资低于mn的不计入离开公司的员工

我的收获:平衡树范围删除,元素个数要用sz[x]来算而非top(因为删除)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int M=100005;
#define son(x,y) c[c[x][y]][y]

int n,top,x,ans,tmp,z,mn;
int c[M][2],sz[M],k[M];
char opt[10];

inline void pushup(int x){sz[x]=sz[c[x][0]]+sz[c[x][1]]+1;}
inline void node(int &x,int v){x=++top;c[x][0]=c[x][1]=0;sz[x]=1;k[x]=v;}

void rotate(int &x,int k)
{
int y=c[x][k^1];
c[x][k^1]=c[y][k];
c[y][k]=x;pushup(y);
pushup(x);x=y;
}

void insert(int &x,int v)
{
if(!x) node(x,v);
else
{
bool m=v>=k[x];
insert(c[x][m],v);
if(sz[son(x,m)]>sz[c[x][m^1]])
rotate(x,m^1);
}
pushup(x);
}

int del(int &x,int v)//这个强啊
{
int t;
if(!x) return 0;
if(k[x]<v) {t=sz[c[x][0]]+1;x=c[x][1];return t+del(x,v);}
else {t=del(c[x][0],v);sz[x]-=t;return t;}
}

int select(int &x,int w)
{
if(!x) return 0;
int r=sz[c[x][0]]+1;
if(w<r) return select(c[x][0],w);
if(w>r) return select(c[x][1],w-r);
return k[x];
}

void work()
{
while(n--){
scanf("%s%d",opt,&z);
if(opt[0]=='I') if(z>=mn) insert(x,z-tmp);
if(opt[0]=='A') tmp+=z;
if(opt[0]=='S'){tmp-=z;ans+=del(x,mn-tmp);}
if(opt[0]=='F'){z=select(x,sz[x]-z+1);printf("%d\n",z?z+tmp:-1);}
}
printf("%d\n",ans);
}

void init(){
x=0;top=0;
cin>>n>>mn;
}

int main()
{
init();
work();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: