HYSBZ - 1503 郁闷的出纳员(Splay)

题目链接:点击查看

题目大意:中文题

题目分析:利用Splay加一点思维还是比较容易解决的,对于所有员工加工资以及减工资的操作,别看只有100次,如果是暴力修改的话,时间复杂度能达到1e7,常数稍大点的模板可能就顶不住了,这里可以思考一下,我们在伸展树中储存的可以是每个员工的相对工资,对于老员工加工资,相对于新员工来说就是减工资了,反之同理,所以我们可以维护一个diff变量,用来记录老员工工资的变动情况,这样对于每个新加入的员工来说,其相对工资就变成了 x - diff 了,其中有个询问第 k 大的员工的工资时,从伸展树中取出数据后别忘了加上 diff 变量恢复到绝对大小,因为在伸展树中保存的是每个员工的相对大小,这样每个操作相对就比较简单了

  1. 新建工作档案:满足条件的直接insert就好了
  2. 加工资:diff += x
  3. 减工资:diff -= x,因为会伴随着些许员工离开公司,我们可以将现在的最低标准:( limit - diff ) 先旋转到根节点,然后其左子树中的所有节点都是小于最低工资标准的员工了,直接删除掉就可以了
  4. 询问第 k 大:这里有个小坑,问的是第 k 大,而不是第 k 小,因为原模板函数求得是第 k 小,所以根据下标转换一下就好了

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;
      
typedef long long LL;
     
typedef unsigned long long ull;
      
const int inf=0x3f3f3f3f;
 
const int N=1e5+100;

int ans=0;

class Splay
{
	public:
	int ch[N][2],f[N],size[N],cnt[N],key[N];//size:子树大小,cnt:当前节点出现次数,key:权值 
	int sz,root;
	inline void clear(int x)
	{
		ch[x][0]=ch[x][1]=f[x]=size[x]=cnt[x]=key[x]=0;
	}
	inline bool get(int x)
	{
		return ch[f[x]][1]==x;
	}
	inline void update(int x)
	{
		if(x)
		{
			size[x]=cnt[x];
			if(ch[x][0]) 
				size[x]+=size[ch[x][0]];
			if(ch[x][1]) 
				size[x]+=size[ch[x][1]];
		}
	}
	inline void rotate(int x)
	{
		int old=f[x],oldf=f[old],whichx=get(x);
		ch[old][whichx]=ch[x][whichx^1]; 
		f[ch[old][whichx]]=old;
		ch[x][whichx^1]=old; 
		f[old]=x;
		f[x]=oldf;
		if(oldf)
			ch[oldf][ch[oldf][1]==old]=x;
		update(old); 
		update(x);
	}
	inline void splay(int x)
	{
		for(int fa;fa=f[x];rotate(x))
		  	if(f[fa])
		    	rotate((get(x)==get(fa))?fa:x);
		root=x;
	}
	inline void insert(int x)
	{
		if(root==0)
		{
			sz++; 
			ch[sz][0]=ch[sz][1]=f[sz]=0; 
			root=sz; 
			size[sz]=cnt[sz]=1; 
			key[sz]=x; 
			return;
		}
		int now=root,fa=0;
		while(1)
		{
			if(x==key[now])
			{
				cnt[now]++; 
				update(now); 
				update(fa); 
				splay(now); 
				break;
			}
			fa=now;
			now=ch[now][key[now]<x];
			if(now==0)
			{
				sz++;
				ch[sz][0]=ch[sz][1]=0;
				f[sz]=fa;
				size[sz]=cnt[sz]=1;
				ch[fa][key[fa]<x]=sz;
				key[sz]=x;
				update(fa);
				splay(sz);
				break;
			}
		}
	}
	inline int find(int x)//查询x的排名
	{
		int now=root,ans=0;
		while(1)
		{
			if(x<key[now])
			  	now=ch[now][0];
			else
			{
				ans+=(ch[now][0]?size[ch[now][0]]:0);
				if(x==key[now])
				{
					splay(now); 
					return ans+1;
				}
				ans+=cnt[now];
				now=ch[now][1];
			}
		}
	}
	inline int findx(int x)//找到排名为x的点
	{
		int now=root;
		while(1)
		{
			if(ch[now][0]&&x<=size[ch[now][0]])
			  	now=ch[now][0];
			else
			{
				int temp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
				if(x<=temp) 
					return key[now];
				x-=temp; 
				now=ch[now][1];
			}
		}
	}
	inline int pre()//小于某个数的最大值 
	{
		int now=ch[root][0];
		while(ch[now][1]) 
			now=ch[now][1];
		return now;
	}
	inline int next()//大于某个数的最小值 
	{
		int now=ch[root][1];
		while(ch[now][0]) 
			now=ch[now][0];
		return now;
	}
	inline void del(int x)
	{
		int whatever=find(x);
		if(cnt[root]>1)
		{
			cnt[root]--; 
			update(root); 
			return;
		}
		if(!ch[root][0]&&!ch[root][1]) 
		{
			clear(root); 
			root=0; 
			return;
		}
		if(!ch[root][0])
		{
			int oldroot=root; 
			root=ch[root][1]; 
			f[root]=0; 
			clear(oldroot); 
			return;
		}
		else if(!ch[root][1])
		{
			int oldroot=root; 
			root=ch[root][0]; 
			f[root]=0; 
			clear(oldroot); 
			return;
		}
		int leftbig=pre(),oldroot=root;
		splay(leftbig);
		ch[root][1]=ch[oldroot][1];
		f[ch[oldroot][1]]=root;
		clear(oldroot);
		update(root); 
	}
	inline void pop(int x)
	{
		insert(x);
		ans+=size[ch[root][0]];
		size[root]-=size[ch[root][0]];
		ch[root][0]=0;
		del(x);
	}
}tree;

int main()
{
#ifndef ONLINE_JUDGE
//	freopen("input.txt","r",stdin);
//	freopen("output.txt","w",stdout);
#endif
//	ios::sync_with_stdio(false);
	int n,m,diff=0;
	scanf("%d%d",&n,&m);
	while(n--)
	{
		char s[5];
		int x;
		scanf("%s%d",s,&x);
		if(s[0]=='I')
		{
			if(x>=m)
				tree.insert(x-diff);
		}
		else if(s[0]=='A')
		{
			diff+=x;
		}
		else if(s[0]=='S')
		{
			diff-=x;
			tree.pop(m-diff);
		}
		else if(s[0]=='F')
		{
			int all=tree.size[tree.root];
			if(x>all)
				printf("%d\n",-1);
			else
				printf("%d\n",tree.findx(all+1-x)+diff);
		}
	}
	printf("%d\n",ans);
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	return 0;
}
发布了672 篇原创文章 · 获赞 26 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/104658498