codeforces 38G Queue splay

题意:有n个人依次排队,每个人都有两个属性值a[ i ]、c[ i ],a[ i ]是重要性值,数值越大越重要,c[ i ]是良心值。假如第i个人来是排

队,初始时他在队尾,如果他的a[ i ]大于排在他前面那位的重要性值,那么两人可以交换位置,每次交换良心值减1,直到他前面的

人的重要性值大于a[ i ]或者良心值为0的时候,问最终n个人的队列次序。

思路:splay的val存重要性值,Max维护当前子树的最大值。假设当前要插入的人的重要性值为val,我们递归插入。当递归到以x为

根的子树时,设此时这人当前的良心值为sz, 那么如果val < x->ch[ 1 ]->Max 或者 val < x->val 或者 sz <= x->ch[1]->s(右子树的结点

个数)时,只能往右子树递归插入,不然往左子树插入。插入完成后,将其旋转至根。因为splay中维护的val是重要性值,而最后输

出的是排第几个位置的是第几个人,所以需要将val值映射一下,详见代码:


// file name: codeforces38G.cpp //
// author: kereo //
// create time:  2014年08月26日 星期二 08时40分02秒 //
//***********************************//
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=100000+100;
const int inf=0x3fffffff;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
int n,top,cnt;
int st[MAXN];
struct node
{
	int s,val,Max;
	node *fa,*ch[2];
}nod[MAXN],nil,*null,*root;
map<int,int>mp;
struct Splay
{
	void init(){
		cnt=top=0;
		nil.s=nil.val=nil.Max=0; null=&nil;
		newnode(root,null,inf); //最左端
		newnode(root->ch[1],root,-1); //最右端
		push_up(root);
	}
	void newnode(node *&x,node *f,int val){ //这也一定要用引用,因为你传入的本质是地址常数,而本身你想修改这个数,所以必须要用引用
		if(top) x=&nod[st[--top]];
		else x=&nod[cnt++];
		x->s=1; x->val=x->Max=val; x->fa=f; x->ch[0]=x->ch[1]=null;
	}
	void push_up(node *x){
		x->s=1; x->Max=x->val;
		if(x->ch[0]!=null) x->s+=x->ch[0]->s, x->Max=max(x->Max,x->ch[0]->Max);	
		if(x->ch[1]!=null) x->s+=x->ch[1]->s, x->Max=max(x->Max,x->ch[1]->Max);
	}
	void rotate(node *x,int d){
		node *y=x->fa; //保证y不为null
		//push_down(y); push_down(x);
		y->ch[d^1]=x->ch[d];
		if(x->ch[d]!=null) x->ch[d]->fa=y;
		x->fa=y->fa;
		if(y->fa!=null){
			int d1=y->fa->ch[0] == y ? 0 : 1;
			y->fa->ch[d1]=x;
		}
		x->ch[d]=y; y->fa=x;
		push_up(y);
	}
	void splay(node *x,node *f){
		//push_down(x);
		while(x->fa!=f){
			node *y=x->fa;
			if(y->fa == f){
				int d=y->ch[0] == x ? 1 : 0;
				rotate(x,d);
			}
			else{
				int d=y->fa->ch[0] == y ? 1 : 0;
				if(y->ch[d] == x){ //之字型
					rotate(x,d^1); rotate(x,d);
				}
				else{//一字型
					rotate(y,d); rotate(x,d);
				}
			}
		}
		push_up(x);
		if(f == null) root=x;
	}
	void insert(node *&x,node *f,int val,int sz){ //考虑能否插到x之前
		if(x == null){
			newnode(x,f,val);
			return ;
		}
		if(val<x->ch[1]->Max || val<x->val || sz<x->ch[1]->s) //注意是sz<x->ch[1]->s,因为里面有一个自己设的R(root)结点
			insert(x->ch[1],x,val,sz);
		else 
			insert(x->ch[0],x,val,sz-x->ch[1]->s-1);
		push_up(x);
	}
}spt;
void dfs(node *x){
	if(x->ch[0]!=null)
		dfs(x->ch[0]);
	if(x->val!=-1 && x->val!=inf)
		printf("%d ",mp[x->val]);
	if(x->ch[1]!=null)
		dfs(x->ch[1]);
}
int main()
{
	while(~scanf("%d",&n)){
		mp.clear(); spt.init();
		for(int i=1;i<=n;i++){
			int a,c;
			scanf("%d%d",&a,&c);
			spt.insert(root,null,a,c);
			spt.splay(&nod[cnt-1],null);
			mp[a]=i;
		}
		dfs(root);
		printf("\n");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值