洛谷题单指南-线性表-P1160 队列安排
原题链接:https://www.luogu.com.cn/problem/P1160
题意解读:本题是双向链表的模拟题,要快速实现M个节点的删除,用数组模拟链表是最佳做法。
解题思路:
双向链表关键要实现好两个操作:
void add(int k, int v); //在第k个节点后增加第v的号节点,即在k号同学右边插入v号同学
void del(int k); //删除第k个节点,即从队列去掉k号同学
只需要实现右边插入就够了,因为左边插入可以转化为:
add(l[k], v); // 在k号左边插入v,等于在k左边节点的右边插入v
双向链链表插入过程图示:
双向链表删除过程图示:
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int head = 0, tail = 1; //链表头、尾节点号
int e[N], l[N], r[N], idx = 2; //e[i]:第i号节点的值、l[i]:第i号节点的左指针、r[i]:第i号节点的右指针 idx:数组下标从2开始,0/1被头、尾节点使用
bool isdel[N]; //是否已经删除
//在idx=k节点右边插入第v号节点
void add(int k, int v)
{
e[idx] = v; //将v号学生加入数组,下标为idx
l[r[k]] = idx; //k号右边节点的左指针指向idx
r[idx] = r[k]; //idx的右指针指向k的右边节点
l[idx] = k; //idx的左指针指向k
r[k] = idx; //k的右指针指向idx
idx++;
}
//删除idx=k节点
void del(int k)
{
if(isdel[k]) return;
l[r[k]] = l[k]; //k右边节点的左指针指向k的左边节点
r[l[k]] = r[k]; //k左边节点的右指针指向k的右边节点
isdel[k] = true;
}
//初始化
void init()
{
r[head] = tail; //把头、尾节点相连
l[tail] = head; //把头、尾节点相连
add(head, 1); //在头节点右边加入1号同学
}
//从左到右输出
void print()
{
for(int i = r[head]; i != tail; i = r[i])
{
cout << e[i] << " ";
}
}
int main()
{
int n, m;
cin >> n;
init(); //初始化
int k, p;
for(int i = 2; i <= n; i++)
{
cin >> k >> p;
if(p == 1) add(k + 1, i); //因为数组0/1号是头、尾节点,第1号学生在下标2的节点,第k号学生在下标k+1的节点
else add(l[k + 1], i);
}
int x;
cin >> m;
while(m--)
{
cin >> x;
del(x + 1);
}
print();
return 0;
}