原題連結: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;
}