题目大意:
一个学校里老师要将班上 N N N 个同学排成一列,同学被编号为 1 ∼ N 1∼N 1∼N,他采取如下的方法:
1、先将 1 1 1 号同学安排进队列,这时队列中只有他一个人;
2、 2 − N 2−N 2−N 号同学依次入列,编号为 i i i 的同学入列方式为:老师指定编号为 i i i 的同学站在编号为 1 ∼ ( i − 1 ) 1∼(i−1) 1∼(i−1) 中某位同学(即之前已经入列的同学)的左边或右边;
3、从队列中去掉 M ( M < N ) M(M<N) M(M<N) 个同学,其他同学位置顺序不变。
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号
说明/提示:
数据范围:
对于 20 20 20% 的数据,有 1 ≤ N ≤ 10 1≤N≤10 1≤N≤10;
对于 40 40 40% 的数据,有 1 ≤ N ≤ 1000 1≤N≤1000 1≤N≤1000;
对于 100 100 100% 的数据,有 1 ≤ N , M ≤ 100000 1≤N,M≤100000 1≤N,M≤100000。
思路/分析:
既然每次新同学入列都是在某个已入列同学的左侧或右侧 那么自然想到用两个数组。
L
[
M
A
X
]
L[MAX]
L[MAX] 和
R
[
M
A
X
]
R[MAX]
R[MAX] 来保存队列信息。
L
[
i
]
、
R
[
i
]
L[i]、R[i]
L[i]、R[i] 分别记录第i个同学左侧同学和右侧同学的编号。(初始化为
0
0
0 )
这样只要知道
K
K
K (即同学的编号)和
P
P
P 的值(
0
0
0 左侧
1
1
1 右侧)就可以直接模拟入队操作。
仔细思考就知道 入队要分两种情况 这里以
p
=
0
p=0
p=0 即插入k号同学左侧为例来说明。
(1)
k
k
k 号同学左侧没有同学 即
L
[
k
]
=
0
L[k]=0
L[k]=0 时:
执行下列操作即可(
i
i
i 为当前入队的同学编号)
L[k]=i;
R[i]=k
(2)
k
k
k 号同学左侧有同学 即
L
[
k
]
!
=
0
L[k]!=0
L[k]!=0 时:
先记录i同学的左右同学编号。(因为后面要修改其左右同学的信息)
然后修改k号同学左侧同学的信息 即 $R[L[k]]=i
最后修改k号同学的信息 即
L
[
k
]
=
i
L[k]=i
L[k]=i。
L[i]=L[k];
R[i]=k;
R[L[k]]=i;
L[k]=i;
到此 我们的入队模拟已经完成了!
那么考虑输出的情。既然是从向右输出编号 那么我们需要最左侧同学的编号。
当然可以循环遍历
L
[
n
]
L[n]
L[n] 数组
L
[
i
]
=
0
L[i]=0
L[i]=0 时的i即是最左侧同学
这里提供另外一种方法 在执行入队操作的时候 我们用
l
e
f
t
left
left 标记最左侧同学的编号。
当
p
=
0
p=0
p=0 且入队操作已经模拟完成时 我们判断L[i]是否为
0
0
0 若为
0
0
0 则
l
e
f
t
=
i
left=i
left=i 否则不做操作。
好了 现在队列的头也有了 终于可以进行输出了!
但是题目还有出队的操作啊 其实没有必要进行出队的模拟了。
我们使用一个
f
l
a
g
flag
flag 数组 初始化为
0
0
0 读入出队的同学编号
i
i
i 然后
f
l
a
g
[
i
]
=
1
flag[i]=1
flag[i]=1。
最后遍历队列的时候 若
f
l
a
g
[
i
]
=
1
flag[i]=1
flag[i]=1则不进行输出即可。
代码:
#include <bits/stdc++.h>
using namespace std;
int L[100005],R[100005],flag[100005];
int main(){
int n,m,left = 1;
cin >> n;
L[1] = 0,R[1] = 0;
for(int i = 2;i <= n;i++){
int temp1,temp2;
cin >> temp1 >> temp2;
if(temp2 == 0){
if(L[temp1] == 0){
L[temp1] = i;
R[i] = temp1;
}else{
L[i] = L[temp1];
R[i] = temp1;
R[L[temp1]] = i;
L[temp1] = i;
}
if(L[i] == 0){
left = i;
}
}else{
if(R[temp1] == 0){
R[temp1] = i;
L[i] = temp1;
}else{
L[i] = temp1;
R[i] = R[temp1];
L[R[temp1]] = i;
R[temp1] = i;
}
}
}
cin >> m;
for(int i = 0;i < m;i++){
int temp1;
cin >> temp1;
flag[temp1] = 1;
}
while(left != 0){
if(!flag[left]){
cout << left << ' ';
}
left = R[left];
}
return 0;
}