【BZOJ 1503】郁闷的出纳员【权值线段树】

本文介绍了一种利用段式树进行高效全局信息维护的方法,特别关注于支持全局k最小值查询、元素的增加与删除、以及查找前驱和后继的操作。通过维护一个全局偏移量来优化大规模数据处理,避免了对每个元素直接进行操作的高成本。文章详细阐述了段式树的构建、插入、更新和查询操作,并通过实例展示了如何在保持代码简洁的同时实现快速响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 维护全局信息,结点记录该值出现的次数。

 支持全局k最小值,可增加删除,查找前驱,后继。相对平衡树,代码简单,快。

当数据较大时,需要离散化。

本题维护一个偏移量,当 A 操作时,不全都加工资 add+=x, S 操作 add-=x 。插入时x - add即可,这样仍然是全局偏移量。

输出+add - base就行,base 是防止负数出现

#include <bits/stdc++.h>
using namespace std;
const int base = 200020;
const int maxn = 400020;
struct	T{
	int l,r,num,lazy;	
}t[maxn*4];// t[p] 表示值遇 l 到 r,num是该数出现次数   
char s[10];
int minn,add;
void build(int p,int l,int r){
	t[p].l = l;	 t[p].r = r; t[p].num = 0; t[p].lazy = 0;
	if(t[p].l==t[p].r) return ;
	int mid = (l+r)>>1;
	build(p*2,l,mid);
	build(p*2+1,mid+1,r);
}
void lazy(int p){
	if(t[p].lazy==0)return ;
	else{
		t[p].lazy = 0; //t[p].num = 0;
		t[p*2].lazy = 1; t[p*2].num = 0;
		t[p*2+1].lazy = 1; t[p*2+1].num = 0;
	}
}
void insert(int p,int x){
	if(t[p].l==t[p].r){
		if(t[p].l==x){
			t[p].num++;//插入就是出现次数++,删除就是-- 
		}
		return ;
	}
	lazy(p);
	int mid = (t[p].l+t[p].r)>>1;
	if(x<=mid)insert(p*2,x);
	else insert(p*2+1,x);
	t[p].num = t[p*2].num + t[p*2+1].num;
}

void update(int p,int x){//工资低于x离开 
	if(t[p].r<x){
		t[p].num = 0; t[p].lazy = 1;
		return ;
	}
	if(t[p].l==t[p].r){
		if(t[p].r<x)t[p].num = 0;
		return ;
	}
	lazy(p);
	int mid = (t[p].l+t[p].r)>>1;
	if(x<=mid){
		update(p*2,x);
	}else{
		update(p*2,x);
		update(p*2+1,x);
	}
	t[p].num = t[p*2].num + t[p*2+1].num;
}
int ask(int p,int k){//查询全局第 k 小,第 n - k + 1 大
//查询n - k + 1小则为查询第k大 
	if(t[p].l==t[p].r)return t[p].l;
	lazy(p);
	if(k<=t[2*p].num)ask(p*2,k);
	else ask(p*2+1,k-t[p*2].num);
}
int main()
{
	int kk,x,sum = 0;
	scanf("%d%d",&kk,&minn);
	build(1,0,400100);
	for(int i=0;i<kk;i++)
	{
		scanf("%s%d",s,&x);
		if(s[0] == 'I')
		{
			if(x < minn) continue;
			sum++;
			insert(1,x-add+base);//add为偏移量,不总体操作 加base防负数
		}
		else if(s[0] == 'A')	add += x;
		else if(s[0] == 'S')
		{
			add -= x;
			update(1,minn-add+base);
		}
		else{
			if(x > t[1].num) printf("-1\n");
			else printf("%d\n",ask(1,t[1].num-x+1)+add-base);
		}
	}
	printf("%d\n",sum-t[1].num);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wym_king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值