传送门
思路
这道题就是一道链表模板题,还是有些巧妙的啦
因为有频繁的插入和删除操作,正好可以用链表做,这里用的是数组模拟的双向链表
首先定义结构体,表示链表的节点,(a[x].l)表示(x)的左边这个同学的编号,(a[x].r)表示(x)的右边同学的编号
struct node {
int l, r;
} a[N];
下面有几个重点操作,分别是左边插入,右边插入,删除操作,以及输出
(可能有些绕口,见谅见谅)
1.左边插入
两个参数表示:将(x)插入到(pos)节点的左边(因为是左边插入嘛)
因为我们把(x)插入到了(pos)的左边,所以(x)的右边节点自然应该为(pos)节点,即(a[x].l=a[pos].r)而(x)的左边节点则为原来(pos)节点的左边节点,即(a[x].l = a[pos].l),这时原本(pos)的左边节点的右边节点就变为了(x),即(a[a[pos].l].r=x),最后(pos)节点的左边节点变为了(x),即(a[pos].l=x),当然顺序是要有的,写错了就可能导致答案错误
inline void addleft(int x, int pos) {
a[x].r = pos;
a[a[pos].l].r = x;
a[x].l = a[pos].l;
a[pos].l = x;
}
2.右边插入
右边插入与左边插入完全相反,这里自己体会
inline void addright(int x, int pos) {
a[x].l = pos;
a[a[pos].r].l = x;
a[x].r = a[pos].r;
a[pos].r = x;
}
3.删除操作
那么如何删除这个节点呢??
我们可以一开始把所有节点的左右节点都定义为(-1),表示没有左右节点,而在插入之后就有了左右节点
我们把当前节点(pos)的左边节点的右边节点设置成(a[pos].r),即(a[a[pos].l].r = a[pos].r),把其右边节点的左边节点设置为(a[pos].l),即(a[a[pos].r].l = a[pos].l),然后删除操作就完成了一半,在遍历时就会直接跳过这个节点,然后把(pos)节点的左右节点都设置为(-1),然后就完成了删除操作
inline void dele(int x) {
if(a[x].l == -1) return;
a[a[x].l].r = a[x].r;
a[a[x].r].l = a[x].l;
a[x].l = -1;
a[x].r = -1;
}
4.输出
那么如何输出呢?
我们在一开始把(0)节点的右边节点设为(1),(1)节点的左边节点设为(0),然后在过程中这些节点的左右节点都发生了变化,但是第一个节点一定是(0)号节点的右边节点,然后循环定义(x)为(x)节点的右边节点,如果不为(-1)就一直输出,这样就完成了输出操作
inline void write() {
int x = a[0].r;
while(1) {
cout << x << ' ';
if(a[x].r == -1) break;
x = a[x].r;
}
}
代码
#include <bits/stdc++.h>
#define N 1000111
using namespace std;
struct node {
int l, r;
} a[N];
int n, m;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for(; isdigit(c); c = getchar()) x = x * 10 + c - 48;
return x * f;
}
inline void addright(int x, int pos) {
a[x].l = pos;
a[a[pos].r].l = x;
a[x].r = a[pos].r;
a[pos].r = x;
}
inline void addleft(int x, int pos) {
a[x].r = pos;
a[a[pos].l].r = x;
a[x].l = a[pos].l;
a[pos].l = x;
}
inline void dele(int x) {
if(a[x].l == -1) return;
a[a[x].l].r = a[x].r;
a[a[x].r].l = a[x].l;
a[x].l = -1;
a[x].r = -1;
}
inline void write() {
int x = a[0].r;
while(1) {
cout << x << ' ';
if(a[x].r == -1) break;
x = a[x].r;
}
}
int main() {
n = read();
int k, p;
for(int i = 1; i <= n; i++) {
a[i].l = a[i].r = -1;
}
a[1].l = 0;
a[0].r = 1;
for(int i = 2; i <= n; i++) {
k = read(), p = read();
if(p == 0) addleft(i, k);
else addright(i, k);
}
m = read();
for(int i = 1; i <= m; i++) {
k = read();
dele(k);
}
write();
return 0;
}