P1160 队列安排

队列安排

题目描述

一个学校里老师要将班上N个同学排成一列,同学被编号为1~N,他采取如下的方法:
  1. 先将 1 1 1号同学安排进队列,这时队列中只有他一个人;

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

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

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

输入输出格式

输入格式


1 1 1行为一个正整数 N N N,表示了有 N N N个同学。

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

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

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

输出格式

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

输入输出样例

输入样例

4
1 0
2 1
1 0
2
3
3

输出样例 #1

2 4 1

说明

样例解释:

将同学 2 2 2插入至同学 1 1 1左边,此时队列为:

21 2 1 21

将同学 3 3 3插入至同学 2 2 2右边,此时队列为:

231 2 3 1 231

将同学 4 4 4插入至同学 1 1 1左边,此时队列为:

2341 2 3 4 1 2341

将同学 3 3 3从队列中移出,此时队列为:

241 2 4 1 241

同学 3 3 3已经不在队列中,忽略最后一条指令

最终队列:

241 2 4 1 241

数据范围

对于 20 % 20\% 20%的数据,有 N ≤ 10 N≤10 N10

对于 40 % 40\% 40%的数据,有 N ≤ 1000 N≤1000 N1000

对于 100 % 100\% 100%的数据,有 N , M ≤ 100000 N, M≤100000 N,M100000

开始用的单向列表,发现双向也可以。但这都会超时。
复杂度可能为O(n*n),找到数据n,操作可以忽略,共n次。
时间浪费在了查找上面。
那我们开个数组,把每个编号同学对号入座,保存他的左右编号。
需要的时候,直接把他拉过来即可。
附上tle代码

#include<iostream>
#include<cstdio>
#include<malloc.h>
using namespace std;
struct node {
	int key;
	struct node* next;
};
int read()
{
	int flag=1,ans=0;
	char am=getchar();
	while((am>'9'||am<'0')&&am!='-') am=getchar();
	if(am=='-') flag=-1,am=getchar();
	while(am>='0'&&am<='9') ans=ans*10+am-'0',am=getchar();
	return ans*flag;
}
void add(int i,int p1,int k,node *head) {
	//       0 左, 1右
	node *am=head;
	node *tep=head->next;
	while(tep) 
	{
		if(tep->key==p1) {
			node *p=(node*)malloc(sizeof(struct node));
			p->key=i;
			if(k==0) {
				p->next=tep;
				am->next=p;
			} else {
				p->next=tep->next;
				tep->next=p;
			}
			return;
		}
		am=tep;
		tep=tep->next;
	}
}
void del(int p1,node *head)
{
	node *tep=head->next;
	node *am=head;
	while(tep)
	{
		if(tep->key==p1)
		{
			am->next=tep->next;
			return;
		}
		am=tep;
		tep=tep->next;
	}
	
}
node* build() {
	node *head=(node*)malloc(sizeof(struct node));
	head->key=-1;
	node *tep=(node*)malloc(sizeof(struct node));
	head->next=tep;
	tep->key=1;
	tep->next=NULL;
	return head;
}
void print(node *head) {
	node *te=head->next;
	while(te) {
		printf("%d ",te->key);
		te=te->next;
	}
}
int main(void) {
	int n,p,k;
	node *head=build();
	n=read();
	for(int i=2; i<=n; i++) {
		p=read();
		k=read();
		add(i,p,k,head);
	}
	int m;
	m=read();
	for(int i=1;i<=m;i++)
	{
		int num;
		num=read();
		del(num,head);
	}
	print(head);

}

pe[0]相当于头结点,不然你去哪里找第一人。
第一次用数组模拟链表,感觉有点新鲜呀。

#include<iostream>
#include<cstdio>
#include<malloc.h>
using namespace std;
struct node {
	int key;
	int next,pre;
};
node pe[100003];
int read()
{
	int flag=1,ans=0;
	char am=getchar();
	while((am>'9'||am<'0')&&am!='-') am=getchar();
	if(am=='-') flag=-1,am=getchar();
	while(am>='0'&&am<='9') ans=ans*10+am-'0',am=getchar();
	return ans*flag;
}
void add(int i,int p1,int k) {
	//k 0 左,1 右
	pe[i].key=i;
	if(k==0)
	{
		pe[i].next=pe[p1].key;
		pe[i].pre=pe[p1].pre;
		pe[pe[p1].pre].next=pe[i].key;
		pe[p1].pre=pe[i].key;
		
	}
	else
	{
		pe[i].next=pe[p1].next;
		pe[i].pre=pe[p1].key;
		pe[pe[p1].next].pre=pe[i].key;
		pe[p1].next=pe[i].key;
	}

}
void del(int p1)
{
	if(pe[p1].key==-1) return;
	pe[pe[p1].pre].next=pe[p1].next;
	pe[pe[p1].next].pre=pe[p1].pre;
	pe[p1].key=-1;
}
node build() {
	pe[0].next=pe[1].key;
	pe[1].next=-1;
	pe[1].pre=0;
	pe[0].pre=-1;
	pe[1].key=1;
}
void print() {
	int tep=pe[0].next;
	while(1)
	{
		if(pe[tep].key)
		{
			if(pe[tep].key!=-1)//说明此人被踢出了
			{
				printf("%d ",tep);
			}
		}
		else break;
		tep=pe[tep].next;
	}
}
int main(void) {
	int n,p,k;
	n=read();
	build();
	for(int i=2; i<=n; i++) {
		p=read();
		k=read();
		add(i,p,k);
	}
	int m;
	m=read();
	for(int i=1;i<=m;i++)
	{
		int num;
		num=read();
		del(num);
	}
	print();
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值