P1486 [NOI2004]郁闷的出纳员[权值线段树]

权值线段树。

我们只用维护一个人是否存在,以及他当前排名,而不关心工资的具体值,这个可以直接算。

不难发现,如果不考虑新的员工,所有员工的工资的差值是不变的。

而加进来一个新的员工时,其工资为\(x\),假设当前工资变化量为\(delta\),那么这个新员工与原来员工工资\(x_i\)的工资差就是\(x-x_i-delta\)

根据这点,我们不难想到对所有员工仅维护\(x_i-delta\)这个东西,询问时加上当前的\(delta\)即可。

即维护一颗权值线段树,维护\(x_i-delta\)出现的次数,并实时整体二分求第k大即可。

注意一些小细节,\(x_i-delta\)有可能为负数,因此我们将维护的值域整体向右平移\(N\)

话说这个题不加lazytag也能轻松跑过,数据真的弱。

参考代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 401000
#define M 200010
#define MOD 2520
#define E 1e-12
using namespace std;
inline int read()
{
	int f=1,x=0;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x*f;
}
struct tree{
	int l,r;
	int sum,rem;
}t[N<<2];
int n,lim,delta,now,go;
inline void pushdown(int p)
{
	if(t[p].rem){
		t[p<<1].sum=t[p<<1|1].sum=0;
		t[p<<1].rem=t[p<<1|1].rem=1;
		t[p].rem=0;
	}
}
inline void pushup(int p){t[p].sum=t[p<<1].sum+t[p<<1|1].sum;}
inline void build(int p,int l,int r)
{
	t[p].l=l,t[p].r=r;
	if(l==r){t[p].sum=0;return;}
	int mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	pushup(p);
} 
inline void change(int p,int x,int val)
{
	if(t[p].l==t[p].r){
		t[p].sum+=val;return;
	}
	pushdown(p);
	int mid=(t[p].l+t[p].r)>>1;
	if(x<=mid) change(p<<1,x,val);
	else change(p<<1|1,x,val);
	pushup(p);
}
inline int query(int p,int k)
{
	if(t[p].l==t[p].r) return t[p].l;
	pushdown(p);
	if(t[p<<1].sum>=k) return query(p<<1,k);
	else return query(p<<1|1,k-t[p<<1].sum);
}
inline void upd(int p,int l,int r)
{
	if(l<=t[p].l&&t[p].r<=r){
		if(t[p].sum) now-=t[p].sum,go+=t[p].sum;
		t[p].sum=0,t[p].rem=1;return;
	}
	pushdown(p);
	int mid=(t[p].l+t[p].r)>>1;
	if(l<=mid) upd(p<<1,l,r);
	if(r>mid) upd(p<<1|1,l,r);
	pushup(p);
}
int main()
{
	n=read(),lim=read();
	char op[2];
	build(1,1,N);
	for(int i=1;i<=n;++i){
		scanf("%s",op);
		int k=read();
		if(op[0]=='I'){
			if(k>=lim) change(1,k-delta+M,1),now++;
		}
		else if(op[0]=='A') delta+=k;
		else if(op[0]=='S') delta-=k,upd(1,1,lim-delta-1+M);
		else if(op[0]=='F'){
			if(k>now) puts("-1");
			else printf("%d\n",query(1,now-k+1)+delta-M);
		}
	}
	cout<<go<<endl;
	return 0;
}
posted @ 2019-11-13 21:52  DarkValkyrie  阅读(218)  评论(0编辑  收藏  举报