[luogu p1160] 队列安排
Posted crab-in-the-northeast
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[luogu p1160] 队列安排相关的知识,希望对你有一定的参考价值。
题面
题目描述
一个学校里老师要将班上(N)个同学排成一列,同学被编号为(1sim N),他采取如下的方法:
- 先将(1)号同学安排进队列,这时队列中只有他一个人;
- (2-N)号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为(1sim (i -1))中某位同学(即之前已经入列的同学)的左边或右边;
- 从队列中去掉(M(M<N))个同学,其他同学位置顺序不变。
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。
输入输出格式
输入格式
第(1)行为一个正整数(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)号同学已经不在队列中则忽略这一条指令。
输出格式
(1)行,包含最多(N)个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。
输入输出样例
输入样例 #1
4
1 0
2 1
1 0
2
3
3
输出样例 #1
2 4 1
说明
样例解释: 将同学(2)插入至同学(1)左边,此时队列为:
(2 1)
将同学(3)插入至同学(2)右边,此时队列为:
(2 3 1)
将同学(4)插入至同学(1)左边,此时队列为:
(2 3 4 1)
将同学(3)从队列中移出,此时队列为: (2 4 1)
同学(3)已经不在队列中,忽略最后一条指令
最终队列:
(2 4 1)
数据范围
对于(20\%)的数据,有(N≤10);
对于(40\%)的数据,有(N≤1000);
对于(100\%)的数据,有(N, M≤100000)。
分析
这道题啊,赤裸裸的链表。我们直接实现一个双向链表就好了。这里使用数组实现双向链表。
我们先定义一个node
节点:
struct node {
int l, r;
}l[100005];
然后初始化这个链表。
void InitList(int n) {
for(int i = 1; i <= n; i++)
l[i].l = l[i].r = -1;//全部初始化为-1
l[0].r = 1;//因为一开始就有编号为1的同学
l[1].l = 0;
return ;
}
可以看到,我们把下标为0
作为双向链表的开始。这可以避免一些问题。
接下来定义addLeft
函数,在pos
位置的左边添加数x
。这就是双向链表的板子了,具体见注释。
void addLeft(int x, int pos) {
l[x].r = pos;//节点x的右边设为pos
l[x].l = l[pos].l;//节点x的左边是pos位置节点的左边节点
l[l[pos].l].r = x;//pos的左边节点的右边节点应该是x
l[pos].l = x;//pos的左边是x
return ;
}
addRight
函数同理。
void addRight(int x, int pos) {
l[x].l = pos;
l[x].r = l[pos].r;
l[l[pos].r].l = x;
l[pos].r = x;
return ;
}
那么怎么删除呢?很简单,我们将要删除的节点x
的两边都设为-1
,然后原来两边的节点中,左边的和右边的跳过节点x
直接link together
。
void DeleteNode(int x) {
if(l[x].l != -1) {
l[l[x].l].r = l[x].r;
l[l[x].r].l = l[x].l;
//Link together
l[x].l = -1;
l[x].r = -1;
//delete node x
}
return ;
}
最后是遍历。由于我们是从下标为0
开始的,从0
开始遍历当前节点的右节点就好了,一直到-1
。
void printList() {
int x = l[0].r;
printf("%d ",x);
while(l[x].r != -1) {
x = l[x].r;
printf("%d ", x);
}
return ;
}
完整代码如下:
代码
/*
* @Author: crab-in-the-northeast
* @Date: 2020-03-07 10:37:45
* @Last Modified by: crab-in-the-northeast
* @Last Modified time: 2020-03-07 12:16:14
*/
#include <iostream>
#include <cstdio>
struct node {
int l, r;
}l[100005];
void InitList(int n) {
for(int i = 1; i <= n; i++)
l[i].l = l[i].r = -1;
l[0].r = 1;
l[1].l = 0;
return ;
}
void addLeft(int x, int pos) {
l[x].r = pos;
l[x].l = l[pos].l;
l[l[pos].l].r = x;
l[pos].l = x;
return ;
}
void addRight(int x, int pos) {
l[x].l = pos;
l[x].r = l[pos].r;
l[l[pos].r].l = x;
l[pos].r = x;
return ;
}
void DeleteNode(int x) {
if(l[x].l != -1) {
l[l[x].l].r = l[x].r;
l[l[x].r].l = l[x].l;
l[x].l = -1;
l[x].r = -1;
}
return ;
}
void printList() {
int x = l[0].r;
printf("%d ",x);
while(l[x].r != -1) {
x = l[x].r;
printf("%d ", x);
}
return ;
}
int main() {
int n;
scanf("%d",&n);
InitList(n);
for(int i = 2; i <= n; i++) {
int pos, dir;
scanf("%d %d",&pos, &dir);
if(dir) addRight(i, pos);
else addLeft(i, pos);
}
int m;
scanf("%d",&m);
for(int i = 1; i <= m; i++) {
int x;
scanf("%d",&x);
DeleteNode(x);
}
printList();
return 0;
}
评测结果
AC 100
:R31453533
以上是关于[luogu p1160] 队列安排的主要内容,如果未能解决你的问题,请参考以下文章