洛谷P1486 [NOI2004] 郁闷的出纳员 【平衡树】

题目链接

题意

给出一个下限 l i m i t limit limit,需要一种数据结构 T T T 支持以下 3 种操作

  1. T T T 中插入一个数 X X X,如果 X X X 小于 l i m i t limit limit 则不插入
  2. T T T中 所有数都加上/减去 X X X,并删去 T T T 中小于 l i m i t limit limit 的数
  3. 查询 T T T 中第 X X X

对于每个操作 3 输出答案,如果 T T T中少于 X X X 个数则输出-1

最后一行输出一共删去了几个数

题解

可以用 fhq treap 来维护,对于减少操作就把小于 X X X的子树拆除来,答案加上其大小并删除,对于加减操作可以用个变量 tag 来缓存,并动态改变limit大小,这样对于操作 1 就可以只变化插入值 X 而不改变整棵树

#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<map>
#include<unordered_map>
#include<set>
#include<vector>
#include<stack>
#include <utility>
#include<list>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<time.h>
#include<random>
using namespace std;
#include<ext/pb_ds/priority_queue.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;
#include<ext/rope>
using namespace __gnu_cxx;

#define int long long
#define PI acos(-1.0)
#define eps 1e-9
#define lowbit(a) ((a)&-(a))
#define mid ((l+r)>>1)
#define mem(x,y) memset(x,y,sizeof x)

const int mod = 1e9+7;
int qpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=(ans*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return ans;
}
const int INF = 0x3f3f3f3f;
const int N = 1e6+10;
int n,lmt,tag,ans;
struct node{
	int l,r;
	int w,key,sz;
}fhq[N];
int root,cnt,x,y,z;
mt19937 rng(233);
void update(int now){fhq[now].sz=fhq[fhq[now].l].sz+fhq[fhq[now].r].sz+1;}
int newnode(int val){
	fhq[++cnt]={0,0,val,rng(),1}; return cnt;
}
void split(int now,int val,int &x,int &y){
	if(!now)x=y=0;
	else{
		if(fhq[now].w<=val)x=now,split(fhq[now].r,val,fhq[now].r,y);
		else y=now,split(fhq[now].l,val,x,fhq[now].l);
		update(now);
	}
}
int merge(int x,int y){
	if(!x||!y) return x|y;
	if(fhq[x].key>fhq[y].key){
		fhq[x].r=merge(fhq[x].r,y),update(x);
		return x;
	}
	else{
		fhq[y].l=merge(x,fhq[y].l),update(y);
		return y;
	}
}
void ins(int val){
	split(root,val,x,y);
	root=merge((merge(x,newnode(val))),y);
}
void up(){
	split(root,lmt-1,x,y);
	ans+=fhq[x].sz,root=y;
}
int ask(int rank){
	if(rank>fhq[root].sz)return -1; rank=fhq[root].sz-rank+1;
	int now=root;
	while(now){
        if(fhq[fhq[now].l].sz+1==rank)break;
        else if(fhq[fhq[now].l].sz>=rank)now=fhq[now].l;
        else rank-=fhq[fhq[now].l].sz+1,now=fhq[now].r;
    }
	return fhq[now].w-tag;
}
#define endl '\n'
signed main(){

	std::ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>lmt;
	while(n--){
		char op; int val; cin>>op>>val;
		if(op=='I')if(val+tag>=lmt)ins(val+tag),up();
		if(op=='A')tag-=val,lmt-=val;
		if(op=='S')tag+=val,lmt+=val,up();
		if(op=='F')cout<<ask(val)<<endl;
	}
	cout<<ans<<endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值