P1486 [NOI2004] 郁闷的出纳员

发布时间 2023-11-17 13:03:59作者: wscqwq

P1486 [NOI2004] 郁闷的出纳员

有两种思路,均使用fhq-treap实现

  1. 维护一个变量delta表示全局偏移量,对于新插入的数减去偏移量。使用fhq-treap,可以分裂出<mid的部分,直接丢掉。
  2. 直接用fhq-treap维护一个类似于线段树的懒标记,每次放在根上即可。

方法1

#include<iostream>
#include<random>
using namespace std;
random_device rnd;
mt19937 rd(rnd());
const int N=100010;
unsigned pri[N];
int n,m,rt,l[N],r[N],v[N],sz[N],idx,ans,delta;
#define up(p) sz[p]=sz[l[p]]+sz[r[p]]+1;
int add(int x){
	v[++idx]=x;
	sz[idx]=1;
	pri[idx]=rd();
	return idx;
}
void split(int p,int &x,int &y,int k){
	if(!p){
	    x=y=0;
	    return;
	}
	if(v[p]<=k){
	    x=p;
	    split(r[p],r[p],y,k);
	}
	else{
	    y=p;
	    split(l[p],x,l[p],k);
	}
	up(p);
}
int merge(int x,int y){
    if(!x||!y)return x|y;
    if(pri[x]>=pri[y]){
        r[x]=merge(r[x],y);
        up(x);
        return x;
    }
    else{
        l[y]=merge(x,l[y]);
        up(y);
        return y;
    }
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin);
	#endif
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;++i){
		char x[3];
		int a,b,k;
		cin>>x>>k;
		if(*x=='I'){
			if(k<m)continue;
			split(rt,a,b,k-1-delta);
			rt=merge(merge(a,add(k-delta)),b);
		}
		else if(*x=='A')
			delta+=k;
		else if(*x=='F'){
		    if(k>sz[rt]){
		        cout<<"-1\n";
		        continue;
		    }
			int p=rt;
			while(p){
				if(k<=sz[r[p]])p=r[p];
				else if(k==sz[r[p]]+1){
					cout<<v[p]+delta<<'\n';
					break;
				}
				else k-=sz[r[p]]+1,p=l[p];
			}
		}
		else{
			delta-=k;
			split(rt,a,b,m-1-delta);
			rt=b;
			ans+=sz[a];
		}
	}
	cout<<ans;
	return 0;
}

方法2

#include<iostream>
#include<random>
using namespace std;
random_device rnd;
mt19937 rd(rnd());
const int N=300010;
unsigned pri[N];
int n,m,rt,l[N],r[N],v[N],sz[N],idx,f[N],ans;
#define up(p) sz[p]=sz[l[p]]+sz[r[p]]+1;
int add(int x){
	v[++idx]=x;
	sz[idx]=1;
	pri[idx]=rd();
	return idx;
}
void ch(int p,int k){
	v[p]+=k,f[p]+=k;
}
void down(int p){
	int &k=f[p];
	if(k)ch(l[p],k),ch(r[p],k),k=0;
}
void split(int p,int &x,int &y,int k){
	if(!p){
	    x=y=0;
	    return;
	}
	down(p);
	if(v[p]<=k){
	    x=p;
	    split(r[p],r[p],y,k);
	}
	else{
	    y=p;
	    split(l[p],x,l[p],k);
	}
	up(p);
}
int merge(int x,int y){
    if(!x||!y)return x|y;
    if(pri[x]>=pri[y]){
        down(x);
        r[x]=merge(r[x],y);
        up(x);
        return x;
    }
    else{
        down(y);
        l[y]=merge(x,l[y]);
        up(y);
        return y;
    }
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin);
	#endif
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;++i){
		char x[2];
		int a,b,k;
		cin>>x>>k;
		if(*x=='I'){
			if(k<m)continue;
			split(rt,a,b,k-1);
			rt=merge(merge(a,add(k)),b);
		}
		else if(*x=='A')
			ch(rt,k);
		else if(*x=='F'){
		    if(k>sz[rt]){
		        cout<<"-1\n";
		        continue;
		    }
			int p=rt;
			while(p){
				down(p);
				if(k<=sz[r[p]])p=r[p];
				else if(k==sz[r[p]]+1){
					cout<<v[p]<<'\n';
					break;
				}
				else k-=sz[r[p]]+1,p=l[p];
			}
		}
		else{
			ch(rt,-k);
			split(rt,a,b,m-1);
			rt=b;
			ans+=sz[a];
		}
	}
	cout<<ans;
	return 0;
}