POJ 3481 Double Queue

题目大意:

        新成立与罗马尼亚布加勒斯特的巴尔干半岛投资集团银行,装备了由IBM公司支持的现代计算环境以及IT技术。通常每个客户在接受服务时都会得到一个编号K和权限P(K < 10^6, P < 10^7)。但是一名经理创造性的提出可以通过低权限(而非高权限)从服务柜台获得服务,因此他建议软件工程师按照如下规则实现该服务系统:

                0表示终止服务系统;

                1 K P表示在等待队列里假如一名编号为K优先级为P的客户;

                2表示为最高权限客户提供服务,并从等待列表中除去该客户;

                3表示为最低权限客户提供服务,并从等待列表中除去该客户;

         对于命令2和3需要输出相应的客户编号(等待列表中各个客户编号和优先级互不相同)。

题目链接

伸展树:

注释代码:

/*              
 * Problem ID : POJ 3481 Double Queue 
 * Author     : Lirx.t.Una              
 * Language   : C++      
 * Run Time   : 235 ms              
 * Run Memory : 176 KB              
*/  

#include <stdio.h>
#include <stdlib.h>

//maximum and minimum priority
//最大和最小的有限权值
#define	MAXP		10000000
#define	MINP		0

struct	Node;

typedef	struct Node		BNode;
typedef	struct Node *	PtNode;
typedef	struct Node *	Tree;

struct	Node {//伸展树结点

	int		k;//客户的服务编号
	int		p;//客户得到的优先权值
	
	Tree	lft;
	Tree	rht;
};

Tree
splay( Tree tree, int p ) {//伸展

	if ( !tree )
		return NULL;

	BNode	node;//用于收取从tree上剪下来的结点
	Tree	tl;//left tree,node的左分支
	Tree	tr;//right tree,node的右分支
	Tree	ttmp;//temporary tree,临时变量,用于旋转

	node.lft = NULL;
	node.rht = NULL;

	tl = &node;
	tr = &node;

	while (1) {
	
		if ( p == tree->p )//查找成功
			break;

		if ( p < tree->p ) {//目标小于当前结点
			            //需向左子树伸展
		
			if ( !tree->lft )//若左子树为空则无法伸展
				       //因此也就到了极限,可以直接退出循环
				break;

			if ( p < tree->lft->p ) {//若目标比左子树还小
				//则在向左子树伸展之前(即嫁接之前)先做一次
				//AVL左旋转,这样可以保证嫁接回来后整个数的
				  //高度可以降低,可以提高查询速率
			
				//常规的AVL左旋转
				ttmp 		= tree->lft;
				tree->lft	= ttmp->rht;
				ttmp->rht	= tree;
				tree		= ttmp;
				
				if ( !tree->lft )//旋转完成后顶点被更新
					       //因此新的顶点的左子树可能为空
						   //若为空则不能再继续向新的左子树伸展
						   //因此必须跳出循环,将剪去的嫁接回来
					break;
			}//对于大于等于左子树的情况,直接减去顶点并外接即可
			//只有当伸展必须向子树的外侧纵深时才需要旋转调整高度

			//将顶点剪去,暂时接在外部两侧的辅助树上
			tr->lft = tree;
			tr		= tree;
			tree	= tree->lft;
		}
		else {//右伸展与左伸展同理
		
			if ( !tree->rht )
				break;

			if ( p > tree->rht->p ) {
			
				ttmp		= tree->rht;
				tree->rht	= ttmp->lft;
				ttmp->lft	= tree;
				tree		= ttmp;

				if ( !tree->rht )
					break;
			}

			tl->rht	= tree;
			tl		= tree;
			tree	= tree->rht;
		}
	}

	//将暂接在外侧树上的子树接回来
	tl->rht		= tree->lft;
	tr->lft		= tree->rht;
	tree->lft	= node.rht;
	tree->rht	= node.lft;

	return tree;
}

Tree
push( Tree tree, int k, int p ) {//插入结点
	               //插入的结点作为新的顶点

	PtNode	node;

	node = (PtNode)malloc( sizeof(BNode) );

	node->k 	= k;
	node->p 	= p;
	node->lft	= NULL;
	node->rht	= NULL;

	if ( !tree )
		return node;

	tree = splay( tree, p );//先按照插入点的权值
	           //将整棵树伸展一遍,这样可以有效
	           //降低树的高度,使之趋于平衡
	           //接着再进行插入
	           //此时顶点的权值和插入结点的权值非常相近

	if ( p < tree->p ) {//若小于顶点
	
		node->lft = tree->lft;
		node->rht = tree;
		tree->lft = NULL;
	}
	else {//大于顶点
	
		node->rht = tree->rht;
		node->lft = tree;
		tree->rht = NULL;
	}

	return node;
}

Tree
pop( Tree tree, int p ) {//删除指定权值的结点
	//本来该函数是只能删除指定权值的结点的,
	  //如果查询不到指定权值的结点将会在伸展后
	  //返回与其最接近的顶点
	//但是这里由于题目的特殊性,只删除最大或最小
	  //权值,因此这里输入的参数p不是MAXP就是MINP
	//因此在splay后,顶点必然就是最大或者最小的
	//因此无论如何都可以删除
	//并且由于题目中要求空树输出0,因此该功能就在函数外
	  //实现了,因此函数内就不再判断树空了

	Tree	ttmp;

	ttmp = splay( tree, p );//伸展,将最大或者最小结点变成顶点
	printf("%d\n", ttmp->k);//输出

	if ( !ttmp->lft )//左子树为空则直接将右子树作为新树
		tree = ttmp->rht;
	else {
	
		//否则用顶点的值对左子树进行伸展
		//由于顶点一定比左子树中任何一个结点的值都大
		//因此伸展后左子树的右子树必为空
		//接着再以伸展后的左子树作为新树
		//将老树的右子树接在其右子树上即可
		tree	  = splay( ttmp->lft, ttmp->p );
		tree->rht = ttmp->rht;
	}
	free(ttmp);

	return tree;
}

int
main() {

	int		n;
	int		k, p;

	Tree	tree;

	tree = NULL;
	while ( scanf("%d", &n), n ) {
	
		switch (n) {
		
			case 1 :
		
				scanf("%d%d", &k, &p);
				tree = push( tree, k, p );
				break;

			case 2 :

				if ( !tree ) {
				
					puts("0");
					break;
				}

				tree = pop( tree, MAXP );
				break;

			default :

				if ( !tree ) {
				
					puts("0");
					break;
				}

				tree = pop( tree, MINP );
				break;
		}
	}

	return 0;
}

无注释代码:

#include <stdio.h>
#include <stdlib.h>

#define	MAXP		10000000
#define	MINP		0

struct	Node;

typedef	struct Node		BNode;
typedef	struct Node *	PtNode;
typedef	struct Node *	Tree;

struct	Node {

	int		k;
	int		p;
	
	Tree	lft;
	Tree	rht;
};

Tree
splay( Tree tree, int p ) {

	if ( !tree )
		return NULL;

	BNode	node;
	Tree	tl;
	Tree	tr;
	Tree	ttmp;

	node.lft = NULL;
	node.rht = NULL;

	tl = &node;
	tr = &node;

	while (1) {
	
		if ( p == tree->p )
			break;

		if ( p < tree->p ) {
		
			if ( !tree->lft )
				break;

			if ( p < tree->lft->p ) {
			
				ttmp 		= tree->lft;
				tree->lft	= ttmp->rht;
				ttmp->rht	= tree;
				tree		= ttmp;
				
				if ( !tree->lft )
					break;
			}

			tr->lft = tree;
			tr		= tree;
			tree	= tree->lft;
		}
		else {
		
			if ( !tree->rht )
				break;

			if ( p > tree->rht->p ) {
			
				ttmp		= tree->rht;
				tree->rht	= ttmp->lft;
				ttmp->lft	= tree;
				tree		= ttmp;

				if ( !tree->rht )
					break;
			}

			tl->rht	= tree;
			tl		= tree;
			tree	= tree->rht;
		}
	}

	tl->rht		= tree->lft;
	tr->lft		= tree->rht;
	tree->lft	= node.rht;
	tree->rht	= node.lft;

	return tree;
}

Tree
push( Tree tree, int k, int p ) {

	PtNode	node;

	node = (PtNode)malloc( sizeof(BNode) );

	node->k 	= k;
	node->p 	= p;
	node->lft	= NULL;
	node->rht	= NULL;

	if ( !tree )
		return node;

	tree = splay( tree, p );

	if ( p < tree->p ) {
	
		node->lft = tree->lft;
		node->rht = tree;
		tree->lft = NULL;
	}
	else {
	
		node->rht = tree->rht;
		node->lft = tree;
		tree->rht = NULL;
	}

	return node;
}

Tree
pop( Tree tree, int p ) {

	Tree	ttmp;

	ttmp = splay( tree, p );
	printf("%d\n", ttmp->k);

	if ( !ttmp->lft )
		tree = ttmp->rht;
	else {
	
		tree	  = splay( ttmp->lft, ttmp->p );
		tree->rht = ttmp->rht;
	}
	free(ttmp);

	return tree;
}

int
main() {

	int		n;
	int		k, p;

	Tree	tree;

	tree = NULL;
	while ( scanf("%d", &n), n ) {
	
		switch (n) {
		
			case 1 :
		
				scanf("%d%d", &k, &p);
				tree = push( tree, k, p );
				break;

			case 2 :

				if ( !tree ) {
				
					puts("0");
					break;
				}

				tree = pop( tree, MAXP );
				break;

			default :

				if ( !tree ) {
				
					puts("0");
					break;
				}

				tree = pop( tree, MINP );
				break;
		}
	}
	
	return 0;
}

STL:

注释代码:

/*              
 * Problem ID : POJ 3481 Double Queue 
 * Author     : Lirx.t.Una              
 * Language   : C++      
 * Run Time   : 297 ms              
 * Run Memory : 196 KB              
*/  

#include <iostream>
#include <cstdio>
#include <map>

using namespace std;

int
main() {
	
	map<int, int>			mp;
	map<int, int>::iterator	it;//迭代器
	
	int		n;
	int		k, p;

	//在map[i] = j中i为第一个参数,j为第二个参数
	//i向j映射
	//其中迭代顺序为按照i的大小从前往后排
	//即map.begin()为i最小的元素的迭代器
	//map.end() - 1为i最大的元素的迭代器
	//迭代器重载过->运算符,其中
	  //it->first为第一个参数,即i
	  //it->second为第二个参数,即j
	//map内部实现为红黑树

	//此程序中map的几个调用
	  //mp.begin()、mp.end()返回起始和末尾元素的迭代器
	    //其中mp.end()指向的是最后一个元素的后面一个位置,其实是空的
	    //因此得到的it需要--
	  //mp.erase(it)将相应迭代器所指向的元素删去
	  //mp.empty()判断map是否为空
	  //it->first、it->second,返回迭代器所指元素的第一和第二参数
	
	while ( scanf("%d", &n), n )
		switch (n) {
		
			case 1 :
				
				scanf("%d%d", &k, &p);
				mp[p] = k;
				break;
				
			case 2 :
				
				if ( mp.empty() ) {
					
					puts("0");
					break;
				}
				
				it = mp.end();
				printf("%d\n", (--it)->second);
				mp.erase(it);
				break;
				
			default :
				
				if ( mp.empty() ) {
					
					puts("0");
					break;
				}
				
				it = mp.begin();
				printf("%d\n", it->second);
				mp.erase(it);
				break;
	}
	
	return 0;
}

无注释代码:

#include <iostream>
#include <cstdio>
#include <map>

using namespace std;

int
main() {

	map<int, int>			mp;
	map<int, int>::iterator	it;

	int		n;
	int		k, p;

	while ( scanf("%d", &n), n )
		switch (n) {
		
			case 1 :

				scanf("%d%d", &k, &p);
				mp[p] = k;
				break;

			case 2 :

				if ( mp.empty() ) {
				
					puts("0");
					break;
				}

				it = mp.end();
				printf("%d\n", (--it)->second);
				mp.erase(it);
				break;

			default :

				if ( mp.empty() ) {
			
					puts("0");
					break;
				}

				it = mp.begin();
				printf("%d\n", it->second);
				mp.erase(it);
				break;
		}

	return 0;
}

树堆(Treap):

注释代码:

/*               
 * Problem ID : POJ 3481 Double Queue  
 * Author     : Lirx.t.Una               
 * Language   : C/C++       
 * Run Time   : 266 ms               
 * Run Memory : 196 KB               
*/    

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

struct	Node;

typedef	struct Node *	PtNode;
typedef struct Node *	Tree;

struct	Node {

	int		k;
	int		p;

	Tree	lft;
	Tree	rht;

	int		fix;//随机修正值
};

Tree
RotL(Tree k2) {//AVL左旋

	Tree	k1;

	k1		= k2->lft;
	k2->lft = k1->rht;
	k1->rht = k2;

	return k1;
}

Tree
RotR(Tree k2) {//AVL右旋

	Tree	k1;

	k1		= k2->rht;
	k2->rht = k1->lft;
	k1->lft = k2;

	return k1;
}

Tree
Insert( Tree tree, int k, int p ) {//插入

	if ( !tree ) {//正常的BST插入,并附上随机修正值
		//插在叶结点上
	
		PtNode	node;

		node = (PtNode)malloc( sizeof( struct Node ) );

		node->k		= k;
		node->p 	= p;
		node->lft	= NULL;
		node->rht 	= NULL;

		node->fix 	= rand();

		return node;
	}

	//调整高度时按照随机修正值小的往高处调的原则进行维护
	//待调结点和顶点比较修正值大小
	if ( p < tree->p ) {
	
		tree->lft = Insert( tree->lft, k, p );
		if ( tree->lft->fix < tree->fix )
			tree = RotL(tree);
	}
	else {
	
		tree->rht = Insert( tree->rht, k, p );
		if ( tree->rht->fix < tree->fix )
			tree = RotR(tree);
	}

	return tree;
}

Tree
Remove( Tree tree, int p ) {//删除相应权值的结点

	if ( !tree )
		return NULL;

	if ( p == tree->p ) {//找到匹配结点
	
		if ( !tree->lft || !tree->rht ) {//可以直接删除

			Tree	ttmp;

			ttmp = tree;

			if ( !tree->lft )
				tree = tree->rht;
			else
				tree = tree->lft;

			free(ttmp);
			return tree;
		}

		//左右子树都非空,必须做调整后在进行删除


		if ( tree->lft->fix < tree->rht->fix ) {
		//按照随机修正值小的结点往上走的原则
        //先将左子树顶点左旋至顶点位置,此时老顶点称为新顶点的右子树顶点了
		//然后在右子树中删除匹配结点就行了
		
		
			tree		= RotL(tree);
			tree->rht	= Remove( tree->rht, p );
		}
		else {//与上对称,同理
		
			tree		= RotR(tree);
			tree->lft	= Remove( tree->lft, p );
		}

		return tree;
	}

	if ( p < tree->p )
		tree->lft = Remove( tree->lft, p );
	else
		tree->rht = Remove( tree->rht, p );

	return tree;
}

int
MinP(Tree tree) {//get minimum priority in tree
	//获得tree中权值最小的顶点的权值

	while ( tree->lft )
		tree = tree->lft;

	printf("%d\n", tree->k);//顺便输出最小结点的编号值
	return tree->p;
}

int
MaxP(Tree tree) {//get maximum priority in tree

	while ( tree->rht )
		tree = tree->rht;

	printf("%d\n", tree->k);
	return tree->p;
}

int
main() {

	int		n;
	int		k, p;

	Tree	tree;

	tree = NULL;
	srand( (unsigned int)time(NULL) );
	while ( scanf("%d", &n), n )
		switch (n) {
		
			case 1 :

				scanf("%d%d", &k, &p);
				tree = Insert( tree, k, p );
				break;

			case 2 :

				if ( !tree ) {
				
					puts("0");
					break;
				}

				tree = Remove( tree, MaxP(tree) );
				break;

			default :

				if ( !tree ) {
				
					puts("0");
					break;
				}

				tree = Remove( tree, MinP(tree) );
				break;
		}

	return 0;
}

无注释代码:

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

struct	Node;

typedef	struct Node *	PtNode;
typedef struct Node *	Tree;

struct	Node {

	int		k;
	int		p;

	Tree	lft;
	Tree	rht;

	int		fix;
};

Tree
RotL(Tree k2) {

	Tree	k1;

	k1		= k2->lft;
	k2->lft = k1->rht;
	k1->rht = k2;

	return k1;
}

Tree
RotR(Tree k2) {

	Tree	k1;

	k1		= k2->rht;
	k2->rht = k1->lft;
	k1->lft = k2;

	return k1;
}

Tree
Insert( Tree tree, int k, int p ) {

	if ( !tree ) {
	
		PtNode	node;

		node = (PtNode)malloc( sizeof( struct Node ) );

		node->k		= k;
		node->p 	= p;
		node->lft	= NULL;
		node->rht 	= NULL;

		node->fix 	= rand();

		return node;
	}

	if ( p < tree->p ) {
	
		tree->lft = Insert( tree->lft, k, p );
		if ( tree->lft->fix < tree->fix )
			tree = RotL(tree);
	}
	else {
	
		tree->rht = Insert( tree->rht, k, p );
		if ( tree->rht->fix < tree->fix )
			tree = RotR(tree);
	}

	return tree;
}

Tree
Remove( Tree tree, int p ) {

	if ( !tree )
		return NULL;

	if ( p == tree->p ) {
	
		if ( !tree->lft || !tree->rht ) {

			Tree	ttmp;

			ttmp = tree;

			if ( !tree->lft )
				tree = tree->rht;
			else
				tree = tree->lft;

			free(ttmp);
			return tree;
		}

		if ( tree->lft->fix < tree->rht->fix ) {
		
			tree		= RotL(tree);
			tree->rht	= Remove( tree->rht, p );
		}
		else {
		
			tree		= RotR(tree);
			tree->lft	= Remove( tree->lft, p );
		}

		return tree;
	}

	if ( p < tree->p )
		tree->lft = Remove( tree->lft, p );
	else
		tree->rht = Remove( tree->rht, p );

	return tree;
}

int
MinP(Tree tree) {

	while ( tree->lft )
		tree = tree->lft;

	printf("%d\n", tree->k);
	return tree->p;
}

int
MaxP(Tree tree) {

	while ( tree->rht )
		tree = tree->rht;

	printf("%d\n", tree->k);
	return tree->p;
}

int
main() {

	int		n;
	int		k, p;

	Tree	tree;

	tree = NULL;
	srand( (unsigned int)time(NULL) );
	while ( scanf("%d", &n), n )
		switch (n) {
		
			case 1 :

				scanf("%d%d", &k, &p);
				tree = Insert( tree, k, p );
				break;

			case 2 :

				if ( !tree ) {
				
					puts("0");
					break;
				}

				tree = Remove( tree, MaxP(tree) );
				break;

			default :

				if ( !tree ) {
				
					puts("0");
					break;
				}

				tree = Remove( tree, MinP(tree) );
				break;
		}

	return 0;
}

单词解释:

found:vt, 创立,创办

Balkan:地名,巴尔干半岛(即意大利陆地)

investment:n, 投资

Bucharest:地名,布加勒斯特(罗马尼亚首都)

equip:vt, 装备

Romania:国家,罗马尼亚

client:n, 客户,客户机

upon:prep, 根据

identify:vt, 鉴定,识别

invention:n, 发明

shock:vt, 震惊

propose:vt, 建议,打算

request:n, 请求,要求

serving desk:n, 服务柜台

identifier:n, 标示符

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值