洛谷题单指南-线性表-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;
}

 

posted @ 2024-03-11 19:41  五月江城  阅读(70)  评论(0编辑  收藏  举报