洛谷題單指南-線性表-P1160 佇列安排

江城伍月發表於2024-03-11

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

雙向鏈連結串列插入過程圖示:

洛谷題單指南-線性表-P1160 佇列安排

雙向連結串列刪除過程圖示:

洛谷題單指南-線性表-P1160 佇列安排

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;
}

相關文章