P1160 队列安排题解

题目

一个学校里老师要将班上N个同学排成一列,同学被编号为1∼N,他采取如下的方法:

  1. 先将1号同学安排进队列,这时队列中只有他一个人;

  2. 2∼N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1∼(i−1)中某位同学(即之前已经入列的同学)的左边或右边;

  3. 从队列中去掉M个同学,其他同学位置顺序不变。

在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。

输入输出格式

输入格式

第一行一个整数N,表示了有N个同学。 

第2∼N行,第i行包含两个整数k,p,其中k为小于i的正整数,p为0或者1。若p为0,则表示将i号同学插入到k号同学的左边,p为1则表示插入到右边。

第N+1行为一个整数M,表示去掉的同学数目。

接下来M行,每行一个正整数x,表示将x号同学从队列中移去,如果x号同学已经不在队列中则忽略这一条指令。

输出格式

一行,包含最多N个空格隔开的整数,表示了队列从左到右所有同学的编号。

输入输出样例

输入样例

4
1 0
2 1
1 0
2
3
3

输出样例

2 4 1

补充知识

链表的使用,可以完成以下的操作,实现一个数据结构,维护一张表(最初只有一个元素1)。支持以下的操作,其中x,y都是int范围内的正整数,且都不一样。

(1)ins_back(x,y):将元素y插入到x后面

(2)ins_front(x,y):将元素y插入到x前面

(3)ask_back(x):询问x后面的元素

(4)ask_front(x):询问x前面的元素

(5)del(x):从表中删除元素x,不改变其他元素的先后顺序

struct node{
	int pre,nxt;//分别记录前驱和后继结点在数组s中的下标
	int key;
	node(int _key=0,int _pre=0,int _nxt=0){
		pre=_pre;
		nxt=_nxt;
		key=_key;
	}
};
node s[100005];
//一个池,以后想要新建一个结点,就从s数组里面拿出一个位置给新结点
//也可以使用指针new,delete实现
int tot=0;//记录s数组目前使用了多少个位置,那么下一个可用的位置就是s[tot+1]
int find(int x){//查找x的结点编号,需要遍历整个链表
    int now=1;
	while(now&&s[now].key!=x){
		now=s[now].nxt;
		return now;
	} 
} 
void ins_back(int x,int y){//y插在x后面 
	int now=find(x);
	s[++tot]=node(y,now,s[now].nxt);
	s[s[now].nxt].pre=tot;
	s[now].nxt=tot;
}
void ins_front(int x,int y){//y插在x前面 
	int now=find(x);
	s[++tot]=node(y,s[now].pre,now);
	s[s[now].pre].nxt=tot;
	s[now].pre=tot;
}
int ask_back(int x){
	int now=find(x);
	return s[s[now].nxt].key;
}
int ask_front(int x){
	int now=find(x);
	return s[s[now].pre].key;
}
void del(int x){
	int now=find(x);
	int le=s[now].pre,rt=s[now].nxt;
	s[le].nxt=rt;
	s[rt].pre=le;
}

当然STL库也提供了链表的相关操作,需要使用list的头文件。支持以下的常用方法。

(1)list<int> a:定义一个int类型的链表a

(2)int arr[5]={1,2,3};lsit<int> a(arr,arr+3):从数组arr中的前三个元素作为链表a的初始值

(3)a.size():返回链表的结点数量

(4)list<int>::iterator it:定义一个名为it的迭代器(指针)

(5)a.begin();a.end():链表开始和末尾的迭代器指针

(6)it++;it--:迭代器指向前一个和后一个元素

(7)a.push_front(x);a.push_back():在链表开头或者末尾插入元素x

(8)a.insert(it,x):在迭代器it的前插入元素x

(9)a.pop_front();a.pop_back():删除链表开头或者末尾

(10)a.erase(it):删除迭代器it所在的元素

(11)for(it=a.begin();it!=a.end();it++):遍历链表

解析

此题目利用一个双向链表维护这个队伍,每个同学记录自己左边和右边的同学。这样各种操作都可以O\left ( 1 \right )的复杂度完成。可以使用上面的链表模板,但是需要稍微修改一下插入函数和删除函数。使用数组index定位某位同学的结点编号,在插入和删除时直接找到这位同学的结点编号,在插入时还要记录下这名同学的结点编号。这样就不需要每次都要遍历整个链表了。

#include<iostream>
using namespace std;
struct node{
	int pre,nxt,key;
	node(int _key=0,int _pre=0,int _nxt=0){
		pre=_pre;
		nxt=_nxt;
		key=_key;
	}
};
node s[100005];
int n,m,tot=0,index[100005]={0};//记录每个位置的结点编号
void ins_back(int x,int y){
	int now=index[x];//查找索引
	s[++tot]=node(y,now,s[now].nxt);
	s[s[now].nxt].pre=tot;
	s[now].nxt=tot;
	index[y]=tot;//记录索引
}
void ins_front(int x,int y){
	int now=index[x];
	s[++tot]=node(y,s[now].pre,now);
	s[s[now].pre].nxt=tot;
	s[now].pre=tot;
	index[y]=tot;
}
void del(int x){
	int now=index[x];
	int le=s[now].pre,rt=s[now].nxt;
	s[le].nxt=rt;
	s[rt].pre=le;
	index[x]=0;
}
int main(){
	int x,k,p,now;
	cin>>n;
	s[0]=node();//令0恒为最左边的结点
	ins_back(0,1);
	for(int i=2;i<=n;i++){
		cin>>k>>p;
		p ? ins_back(k,i):ins_front(k,i);
	}
	cin>>m;
	for(int i=1;i<=m;i++){
		cin>>x;
		if(index[x]){
			del(x);
		}
	}
	now=s[0].nxt;
	while(now){
		cout<<s[now].key<<" ";
		now=s[now].nxt;
	}
	return 0;
}
  • 12
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值