题目描述
一个学校里老师要将班上N个同学排成一列,同学被编号为1∼N,他采取如下的方法:
先将1号同学安排进队列,这时队列中只有他一个人;
2-N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1∼(i−1)中某位同学(即之前已经入列的同学)的左边或右边;
从队列中去掉M(M<N)个同学,其他同学位置顺序不变。
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。
输入格式
第1行为一个正整数N,表示了有N个同学。
第2−N行,第i行包含两个整数k,p,其中k为小于i的正整数,p为0或者1。若p为0,则表示将i号同学插入到kk号同学的左边,p为1则表示插入到右边。
第N+1行为一个正整数M,表示去掉的同学数目。
接下来M行,每行一个正整数x,表示将x号同学从队列中移去,如x号同学已经不在队列中则忽略这一条指令。
输出格式
1行,包含最多N个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。
输入输出样例
输入
4
1 0
2 1
1 0
2
3
3
输出
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。
解题思路:
虽然表面看起来像是一道队列的题,但是仔细想想你就会发现,用队列并不是很好做,他每次删除一个元素的时候都会使他前后的元素位置发生改变。这时候你就会发现,用链表就显得很合适。因为他是一串操作,并且每次操作都是把相应位置的元素移走,然后再把前面的元素和后面的元素连接起来。并且,他每个元素只出现一次,因此用双向链表就会很好的达到我们的目的。
有的同学可能会说链表我并不熟悉,不是很会使用只是数据结构接触过(比如我),不过你用一个结构体数组还是很好实现的,因为这真的只是一道水题。
AC代码:
#include<iostream>
#include<bits/stdc++.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<string>
using namespace std;
const int N = 1e6+10;
struct line
{
int pr, ne;
bool mk;
}a[N];
int f[N];
int n , m;
int ans = 0;
int main()
{
cin >> n;
int i , j;
int k , p;
a[0].ne = 1;
a[0].pr = 0;
a[1].mk = 1;
a[1].pr = 0;
for(i = 2 ; i <= n ; i++)
{
cin >> k >> p;
a[i].mk = 1;
if(p == 0)
{
a[a[k].pr].ne = i;
a[i].pr = a[k].pr;
a[k].pr = i;
a[i].ne = k;
}
else
{
a[a[k].ne].pr = i;
a[i].pr = k;
a[i].ne = a[k].ne;
a[k].ne = i;
}
}
cin >> m;
int x;
for(i = 1 ; i <= m ; i++)
{
cin >> x;
if(!a[x].mk)
{
continue;
}
a[x].mk = 0;
a[a[x].pr].ne = a[x].ne;
a[a[x].ne].pr = a[x].pr;
}
printf("%d",a[0].ne);
int now = a[0].ne;
now = a[now].ne;
while(now)
{
printf(" %d",now);
now = a[now].ne;
}
cout << endl;
return 0;
}