题目传送门
一、双链表示意图
二、C++代码
#include <bits/stdc++.h>
using namespace std;
//双链表模板
const int N = 100010;
int e[N]; //数据
int l[N]; //左链表
int r[N]; //右链表
int idx; //准备放入的索引值
//正整数x,表示将x号同学从队列中移去,如果x号同学已经不在队列中则忽略这一条指令。
//正是因为有了这句话,如果没有删除的标识了,真的有重复指令就会让数据出问题。
// 因为可能重复的对左右结点进行操作,造成数据错误。
int st[N]; //删除标识
// 黄海写的题解
// https://www.acwing.com/solution/content/35794/
//0表示头,1表示尾,正式使用的是从idx=2开始
void init() {
//0的右端是1,1的左端是0
r[0] = 1, l[1] = 0, idx = 2;
}
//函数含义:在k号节点右侧插入,值为x
//如果想实现:在k号节点左侧插入,值为x 则调用:add(l[k],x),意义为在k的左侧,
//相当于在k的左侧节点的右侧,
void add(int k, int x) {
e[idx] = x; //将x放入到一个空的单元格中
l[idx] = k; //将新增加的单元格的右指针指向k的下一链路节点
r[idx] = r[k]; //将新增加的单元格的左指针指向k
//完成上面两步后,只是让idx这个节点建立了与原来两个节点的关系,而原来的两个k与r[k],
// l[r[k]]还是旧的值,也需要进行修改。
l[r[k]] = idx;
r[k] = idx;
//为下一次做准备
idx++;
}
//删除第k个节点
void remove(int k) {
r[l[k]] = r[k];
l[r[k]] = l[k];
}
int n, k, p, m, x;
//输出双链表
void print() {
//遍历双向链表的方法
for (int i = r[0]; i != 1; i = r[i]) cout << e[i] << " ";
cout << endl;
}
int main() {
//初始化双链表
init();
//读入
cin >> n;
//先将1号同学安排进队列
//最左端就是表示在head(0号)的右侧插入一个数据
add(0, 1);
for (int i = 2; i <= n; i++) {
//k为小于i的正整数
cin >> k >> p;
//p为0,表示将i号同学插入到k号同学的左边
//p为1,表示将i号同学插入到k号同学的右边
//idx从2开始,所以下标需要k+1传入才对
//就是1号同学的idx=2
//就是2号同学的idx=3
//就是3号同学的idx=4
//就是k号同学的idx=k+1
//右边就是正常的add(k+1,i)
//左边稍有一点变化:add(l[k+1],i), 表示在当前号的左侧那个,就是它的前面结点的右侧放入
if (p == 0) add(l[k + 1], i);
else add(k + 1, i);
}
//表示去掉的同学数目
cin >> m;
for (int i = 1; i <= m; i++) {
cin >> x;
//表示将x号同学从队列中移去
if (!st[x + 1]) {
remove(x + 1);
st[x + 1] = 1;
}
}
//输出链表 (表示了队列从左到右所有同学的编号,行末换行且无空格)
print();
return 0;
}