POJ 3481 Double Queue [splay]

题意:有三种操作:1.将权值为p名称为k的顾客加入队列 2.从队列中取出权值较高的顾客,并输出 3.从队列中取出权值较低的顾客并输出

题解:用splay维护权值,再询问

AC代码:

#include<stdio.h>
#include<string.h>
#include<map>
using namespace std;
#define MAXN 1000005 //节点数 
int ch[MAXN][2],f[MAXN],cnt[MAXN],key[MAXN],size[MAXN];
int sz=0,root=0; 
int newnode(int fa,int v)
{
	sz++;
	ch[sz][0]=ch[sz][1]=0;
	f[sz]=fa;key[sz]=v;
	size[sz]=cnt[sz]=1;
	return sz;
}
void clear(int x)
{
	ch[x][0]=ch[x][1]=f[x]=cnt[x]=key[x]=size[x]=0;
}
int get(int x)//得到x是其父亲的左儿子还是右儿子 
{
 	return ch[f[x]][1]==x;
}
void up(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]];
   	}
}
void rotate(int x)
{
	int old=f[x],oldf=f[old],which=get(x);
	ch[old][which]=ch[x][which^1];f[ch[old][which]]=old;
	f[old]=x;ch[x][which^1]=old;
	f[x]=oldf;
	if(oldf)ch[oldf][ch[oldf][1]==old]=x;
	up(old);up(x);
}
void splay(int x,int goal)//伸展
{
 	for(int fa;(fa=f[x]);rotate(x))
 		if(f[fa]!=goal)
			rotate((get(x)==get(fa)?fa:x));
   	if(goal==0)root=x;
}
void insert(int v)
{
	if(root==0)
	{
		root=newnode(0,v);
		return;
	}
	int now=root,fa=0;
	while(1)
	{
		if (key[now]==v)
	  	{
   			cnt[now]++;
			up(now);up(fa);
			splay(now,0);break;
  		}
		fa=now;
		now=ch[now][key[now]<v];
		if(now==0)
		{
			int newroot=newnode(fa,v);
			ch[fa][key[fa]<v]=newroot;
			up(fa);
			splay(sz,0);
			break;
		}
	}
}
int find(int v)//查询v的排名
{  
	int ans=0,now=root;
 	while(1)
 	{
		if(v<key[now])
			now=ch[now][0];
		else
		{
			ans+=(ch[now][0]?size[ch[now][0]]:0);
			if(v==key[now])
			{
				splay(now,0);
				return ans+1;
			}
			ans+=cnt[now];
			now=ch[now][1];
		}
	}
}
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];
		}
   	}
}
int pre()
{
	int now=ch[root][0];
	while(ch[now][1])now=ch[now][1];
	return now;
}
int next()
{
	int now=ch[root][1];
	while(ch[now][0])now=ch[now][0];
	return now;
}
void del(int x)//删除某权值的点 
{
	int whatever=find(x);
	if (cnt[root]>1) {cnt[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,0);
   	f[ch[oldroot][1]]=root;
   	ch[root][1]=ch[oldroot][1];
   	clear(oldroot);
   	up(root);
   	return;
}
map<int,int>mp;
int main()
{
	int op;
	while(~scanf("%d",&op))
	{
		if(op==0)break;
		if(op==1)
		{
			int k,v;
			scanf("%d%d",&k,&v);
			insert(v);
			mp[v]=k;
		}
		if(op==2)
		{
			if(size[root]==0)
			{
				printf("0\n");
				continue;
			}
			int v=findx(size[root]);
			printf("%d\n",mp[v]);
			del(v); 
		}
		if(op==3)
		{
			if(size[root]==0)
			{
				printf("0\n");
				continue;
			}
			int v=findx(1);
			printf("%d\n",mp[v]);
			del(v);
		}
	}
} 


splay模板:

#define MAXN 100005 //节点数 
int ch[MAXN][2],f[MAXN],cnt[MAXN],key[MAXN],size[MAXN];
int sz=0,root=0; 
int newnode(int fa,int v)
{
	sz++;
	ch[sz][0]=ch[sz][1]=0;
	f[sz]=fa;key[sz]=v;
	size[sz]=cnt[sz]=1;
	return sz;
}
void clear(int x)
{
	ch[x][0]=ch[x][1]=f[x]=cnt[x]=key[x]=size[x]=0;
}
int get(int x)//得到x是其父亲的左儿子还是右儿子 
{
 	return ch[f[x]][1]==x;
}
void up(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]];
   	}
}
void rotate(int x)
{
	int old=f[x],oldf=f[old],which=get(x);
	ch[old][which]=ch[x][which^1];f[ch[old][which]]=old;
	f[old]=x;ch[x][which^1]=old;
	f[x]=oldf;
	if(oldf)ch[oldf][ch[oldf][1]==old]=x;
	up(old);up(x);
}
void splay(int x,int goal)//伸展
{
 	for(int fa;(fa=f[x]);rotate(x))
 		if(f[fa]!=goal)
			rotate((get(x)==get(fa)?fa:x));
   	if(goal==0)root=x;
}
void insert(int v)
{
	if(root==0)
	{
		root=newnode(0,v);
		return;
	}
	int now=root,fa=0;
	while(1)
	{
		if (key[now]==v)
	  	{
   			cnt[now]++;
			up(now);up(fa);
			splay(now,0);break;
  		}
		fa=now;
		now=ch[now][key[now]<v];
		if(now==0)
		{
			int newroot=newnode(fa,v);
			ch[fa][key[fa]<v]=newroot;
			up(fa);
			splay(sz,0);
			break;
		}
	}
}
int find(int v)//查询v的排名
{  
	int ans=0,now=root;
 	while(1)
 	{
		if(v<key[now])
			now=ch[now][0];
		else
		{
			ans+=(ch[now][0]?size[ch[now][0]]:0);
			if(v==key[now])
			{
				splay(now,0);
				return ans+1;
			}
			ans+=cnt[now];
			now=ch[now][1];
		}
	}
}
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];
		}
   	}
}
int pre()
{
	int now=ch[root][0];
	while(ch[now][1])now=ch[now][1];
	return now;
}
int next()
{
	int now=ch[root][1];
	while(ch[now][0])now=ch[now][0];
	return now;
}
void del(int x)//删除某权值的点 
{
	int whatever=find(x);
	if (cnt[root]>1) {cnt[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,0);
   	f[ch[oldroot][1]]=root;
   	ch[root][1]=ch[oldroot][1];
   	clear(oldroot);
   	up(root);
   	return;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值