对于元素是有序号的插入删除操作,可以采用这种实现起来很简单的链表.
M<N<=100000
如果使用STL的链表,矛盾的地方在于它的迭代器不能随机访问,找到k号同学需要O(N),题解区有一种用数组记录迭代器的方法,看起来很繁琐.
这里采用的方法是记录1~N号节点的信息,有且仅有:
- 该节点编号对应的同学左侧,右侧同学的编号(若没有则为0)
- 该节点编号的同学是否存在
那么只需要设置这样的节点数组:
struct S{ int l, r; bool is; // 是否存在 }s[100010];
想要进行插入操作很简单,更新涉及到的两个节点的信息即可:
if(!p){ s[i].r = k; s[i].l = s[k].l; s[s[k].l].r = i; s[k].l = i; }else{ s[i].r = s[k].r; s[i].l = k; s[s[k].r].l = i; s[k].r = i; }
此外,通过懒惰删除可以很轻松处理第二阶段的数据.
bool killed[100010];
此题需要注意输出格式,末尾不可有空格且需要换行.

#include <algorithm> #include <cstdio> #include <cstring> #include <iostream> using namespace std; struct S{ int l, r; bool is; }s[100010]; int n, m; bool killed[100010]; int main(){ scanf("%d", &n); s[1].is = true; for(int i = 2; i <= n; i++){ int k, p; scanf("%d%d", &k, &p); s[i].is = true; if(!p){ s[i].r = k; s[i].l = s[k].l; s[s[k].l].r = i; s[k].l = i; }else{ s[i].r = s[k].r; s[i].l = k; s[s[k].r].l = i; s[k].r = i; } } int p; for(int i = 1; i <= n; i++) if(s[i].is && !s[i].l){ p = i; break; } scanf("%d", &m); while(m--){ int x; scanf("%d", &x); killed[x] = true; } bool first = true; while(n--){ if(s[p].is && !killed[p]){ if(!first) printf(" "); printf("%d", p); first = false; } p = s[p].r; } puts(""); return 0; }