洛谷 P1160 队列安排
题目描述
一个学校里老师要将班上NN个同学排成一列,同学被编号为1sim N1∼N,他采取如下的方法:
- 先将11号同学安排进队列,这时队列中只有他一个人;
- 2-N2−N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1sim (i -1)1∼(i−1)中某位同学(即之前已经入列的同学)的左边或右边;
- 从队列中去掉M(M<N)M(M<N)个同学,其他同学位置顺序不变。
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。
输入格式
第11行为一个正整数NN,表示了有NN个同学。
第2-N2−N行,第ii行包含两个整数k,pk,p,其中kk为小于ii的正整数,pp为00或者11。若pp为00,则表示将ii号同学插入到kk号同学的左边,pp为11则表示插入到右边。
第N+1N+1行为一个正整数MM,表示去掉的同学数目。
接下来MM行,每行一个正整数xx,表示将xx号同学从队列中移去,如果xx号同学已经不在队列中则忽略这一条指令。
输出格式
11行,包含最多NN个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。
输入输出样例
输入 #1复制
输出 #1复制
说明/提示
样例解释:
将同学22插入至同学11左边,此时队列为:
2 121
将同学33插入至同学22右边,此时队列为:
2 3 1231
将同学44插入至同学11左边,此时队列为:
2 3 4 12341
将同学33从队列中移出,此时队列为:
2 4 1241
同学33已经不在队列中,忽略最后一条指令
最终队列:
2 4 1241
数据范围
对于20%20%的数据,有N≤10N≤10;
对于40%40%的数据,有N≤1000N≤1000;
对于100%100%的数据,有N, M≤100000N,M≤100000。
题解:
我们非常容易得出,这道题的大意就是在一个数列里进行大量的随机插入和随机删除操作,一看就是一道数据结构的题目。
那么用什么数据结构呢?
队列?肯定不行,队列不支持随机插入和删除。
数组?那不扯呢么
栈?(狗屁)
我们找遍所有容器,发现根本没有支持随机插入和删除的。
于是我们开动了百度,上网查询到了链表。
链表是一种支持随机插入和随机删除的数据结构。
链表相关知识链接:
所以我们发现这道题一下子就变成了一道链表数据结构的裸题。
套用数组模拟链表进行AC操作即可。
代码:
#include<cstdio>
using namespace std;
int n,m;
struct node
{
int pre,nxt;
}a[100010];
void init()
{
for(int i=1;i<=n;i++)
a[i].pre=a[i].nxt=-1;
a[1].nxt=-1;
a[1].pre=0;
a[0].nxt=1;
}
void insert_left(int pos,int k)
{
a[a[pos].pre].nxt=k;
a[k].pre=a[pos].pre;
a[pos].pre=k;
a[k].nxt=pos;
}
void insert_right(int pos,int k)
{
a[a[pos].nxt].pre=k;
a[k].nxt=a[pos].nxt;
a[pos].nxt=k;
a[k].pre=pos;
}
void remove(int x)
{
if(a[x].pre==-1)
return;
a[a[x].pre].nxt=a[x].nxt;
a[a[x].nxt].pre=a[x].pre;
a[x].pre=-1;
a[x].nxt=-1;
}
void print()
{
int start=a[0].nxt;
while(1)
{
printf("%d ",start);
if(a[start].nxt==-1)
break;
start=a[start].nxt;
}
}
int main()
{
scanf("%d",&n);
init();
for(int i=2;i<=n;i++)
{
int k,p;
scanf("%d%d",&k,&p);
if(p==1)
insert_right(k,i);
else
insert_left(k,i);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
remove(x);
}
print();
return 0;
}