950. 郁闷的出纳员

题目链接

950. 郁闷的出纳员

OIER 公司是一家大型专业化软件公司,有着数以万计的员工。

作为一名出纳员,我的任务之一便是统计每位员工的工资。

这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。

如果他心情好,就可能把每位员工的工资加上一个相同的量。

反之,如果心情不好,就可能把他们的工资扣除一个相同的量。

我真不知道除了调工资他还做什么其它事情。

工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。

每位员工的工资下界都是统一规定的。

每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。

老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第 \(k\) 多的员工拿多少工资。

每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。

好了,现在你已经对我的工作了解不少了。

正如你猜的那样,我想请你编一个工资统计程序。

怎么样,不是很困难吧?

输入格式

第一行有两个非负整数 \(n\)\(min\)\(n\) 表示下面有多少条命令,\(min\) 表示工资下界。

接下来的 \(n\) 行,每行表示一条命令,命令可以是以下四种之一:

  1. I 命令,格式为 I_k,表示新建一个工资档案,初始工资为 \(k\)。如果某员工的初始工资低于工资下界,他将立刻离开公司。
  2. A 命令,格式为 A_k,表示把每位员工的工资加上 \(k\)
  3. S 命令,格式为 S_k,表示把每位员工的工资扣除 \(k\)
  4. F 命令,格式为 F_k,表示查询第 \(k\) 多的工资。

_(下划线)表示一个空格,I 命令、A 命令、S 命令中的 \(k\) 是一个非负整数,F 命令中的 \(k\) 是一个正整数。

在初始时,可以认为公司里一个员工也没有。

输出格式

输出行数为 \(F\) 命令的条数加一。

对于每条 \(F\) 命令,你的程序要输出一行,仅包含一个整数,为当前工资第 \(k\) 多的员工所拿的工资数,如果 \(k\) 大于目前员工的数目,则输出 \(-1\)

输出文件的最后一行包含一个整数,为离开公司的员工的总数。

注意,如果某个员工的初始工资低于最低工资标准,那么将不计入最后的答案内。

数据范围

I 命令的条数不超过 \(10^5\)
A 命令和 S 命令的总条数不超过 \(100\)
F 命令的条数不超过 \(10^5\)
每次工资调整的调整量不超过 \(1000\)
新员工的工资不超过 \(10^5\)

输入样例:

9 10
I 60
I 70
S 50
F 2
I 30
S 15
A 5
F 1
F 2

输出样例:

10
20
-1
2

解题思路

splay

由于每次插入一个数,都按照值在中序遍历中的位置插入,而所有的操作都不改变 \(splay\) 所维护的中序遍历的顺序,所以整个操作中 \(splay\) 维护的中序遍历的值是有序的,而本题关键在于删除一个区间,删除一个区间往往引入两个哨兵 \(-inf,inf\),其中 \(L\) 表示值为 \(-inf\) 的节点,不妨用 \(d\) 记下目前增减操作的值,而每次删除节点时,要求删除的节点表示的值 \(x\),满足 \(-inf<x+d<mn\),则需删除 \(splay\) 中表示值为 \([0,mn-d)\) 的节点,则需将这些节点放在一棵子树上便于删除,则需找到最小满足 \(x\geq mn-d\)\(x\) 的代表的节点 \(R\),然后有两种方法将所求区间变为一棵子树:1. \(splay(R,0),splay(L,R)\),此时 \(L\) 的右子树即为所求;2. \(splay(L,0),splay(R,L)\),此时 \(R\) 的左子树即为所求

  • 时间复杂度:\(O(nlogn)\)

代码

// Problem: 郁闷的出纳员
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/952/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1e5+5,inf=1e8;
int root,cnt,d,n,mn,k,res;
struct Tr
{
	int s[2],sz,p,v;
	void init(int _p,int _v)
	{
		p=_p,v=_v;
	}
}tr[N];
void pushup(int u)
{
	tr[u].sz=tr[tr[u].s[0]].sz+tr[tr[u].s[1]].sz+1;
}
void rotate(int x)
{
	int y=tr[x].p,z=tr[y].p;
	int k=tr[y].s[1]==x;
	tr[z].s[tr[z].s[1]==y]=x,tr[x].p=z;
	tr[y].s[k]=tr[x].s[k^1],tr[tr[x].s[k^1]].p=y;
	tr[x].s[k^1]=y,tr[y].p=x;
	pushup(y),pushup(x);
}
void splay(int x,int k)
{
	while(tr[x].p!=k)
	{
		int y=tr[x].p,z=tr[y].p;
		if(z!=k)
		{
			if((tr[z].s[1]==y)^(tr[y].s[1]==x))rotate(x);
			else
				rotate(y);
		}
		rotate(x);
	}
	if(!k)root=x;
}
int insert(int v)
{
	int u=root,p=0;
	while(u)p=u,u=tr[u].s[v>tr[u].v];
	u=++cnt;
	if(p)tr[p].s[v>tr[p].v]=u;
	tr[u].init(p,v);
	splay(u,0);
	return u;
}
int find(int val)
{
	int u=root,res=-1;
	while(u)
	{
		if(tr[u].v>=val)res=u,u=tr[u].s[0];
		else
			u=tr[u].s[1];
	}
	return res;
}
int get_k(int k)
{
	int u=root;
	while(u)
	{
		if(tr[tr[u].s[0]].sz>=k)u=tr[u].s[0];
		else if(tr[tr[u].s[0]].sz+1==k)return tr[u].v;
		else
			k-=tr[tr[u].s[0]].sz+1,u=tr[u].s[1];
	}
	return -1;
}
int main()
{
    scanf("%d%d",&n,&mn);
    int L=insert(-inf),R=insert(inf);
    while(n--)
    {
    	char op[2];
    	scanf("%s%d",op,&k);
    	if(*op=='I')
    	{
    		if(k>=mn)insert(k-d),res++;
    	}
    	else if(*op=='A')d+=k;
    	else if(*op=='S')
    	{
    		d-=k;
    		int R=find(mn-d);
    // 		splay(R,0),splay(L,R);
    // 		tr[L].s[1]=0;
    // 		pushup(R),pushup(L);
    		splay(R,0),splay(L,R);
    		tr[L].s[1]=0;
    		pushup(L),pushup(R);
    	}
    	else
    	{
    		if(tr[root].sz-2<k)puts("-1");
    		else
    			printf("%d\n",get_k(tr[root].sz-k)+d);
    	}
    }
    printf("%d",res+2-tr[root].sz);
    return 0;
}
posted @ 2022-07-09 01:26  zyy2001  阅读(16)  评论(0编辑  收藏  举报