Forever Young

洛谷 P1160 队列安排

传送门

我在这里

思路

这道题就是一道链表模板题,还是有些巧妙的啦

因为有频繁的插入和删除操作,正好可以用链表做,这里用的是数组模拟的双向链表

首先定义结构体,表示链表的节点,\(a[x].l\)表示\(x\)的左边这个同学的编号,\(a[x].r\)表示\(x\)的右边同学的编号

struct node {
    int l, r;
} a[N];

下面有几个重点操作,分别是左边插入,右边插入,删除操作,以及输出

(可能有些绕口,见谅见谅)

1.左边插入

两个参数表示:将\(x\)插入到\(pos\)节点的左边(因为是左边插入嘛)

因为我们把\(x\)插入到了\(pos\)的左边,所以\(x\)的右边节点自然应该为\(pos\)节点,即\(a[x].l=a[pos].r\)\(x\)的左边节点则为原来\(pos\)节点的左边节点,即\(a[x].l = a[pos].l\),这时原本\(pos\)的左边节点的右边节点就变为了\(x\),即\(a[a[pos].l].r=x\),最后\(pos\)节点的左边节点变为了\(x\),即\(a[pos].l=x\),当然顺序是要有的,写错了就可能导致答案错误

inline void addleft(int x, int pos) {
    a[x].r = pos;
    a[a[pos].l].r = x;
    a[x].l = a[pos].l;
    a[pos].l = x;
}

2.右边插入

右边插入与左边插入完全相反,这里自己体会

inline void addright(int x, int pos) {
    a[x].l = pos;
    a[a[pos].r].l = x;
    a[x].r = a[pos].r;
    a[pos].r = x;
}

3.删除操作

那么如何删除这个节点呢??

我们可以一开始把所有节点的左右节点都定义为\(-1\),表示没有左右节点,而在插入之后就有了左右节点

我们把当前节点\(pos\)的左边节点的右边节点设置成\(a[pos].r\),即\(a[a[pos].l].r = a[pos].r\),把其右边节点的左边节点设置为\(a[pos].l\),即\(a[a[pos].r].l = a[pos].l\),然后删除操作就完成了一半,在遍历时就会直接跳过这个节点,然后把\(pos\)节点的左右节点都设置为\(-1\),然后就完成了删除操作

inline void dele(int x) {
    if(a[x].l == -1) return;
    a[a[x].l].r = a[x].r;
    a[a[x].r].l = a[x].l;
    a[x].l = -1;
    a[x].r = -1;
}

4.输出

那么如何输出呢?

我们在一开始把\(0\)节点的右边节点设为\(1\),\(1\)节点的左边节点设为\(0\),然后在过程中这些节点的左右节点都发生了变化,但是第一个节点一定是\(0\)号节点的右边节点,然后循环定义\(x\)\(x\)节点的右边节点,如果不为\(-1\)就一直输出,这样就完成了输出操作

inline void write() {
    int x = a[0].r;
    while(1) {
        cout << x << ' ';
        if(a[x].r == -1) break;
        x = a[x].r;
    }
}

代码

#include <bits/stdc++.h>
#define N 1000111
using namespace std;

struct node {
    int l, r;
} a[N];

int n, m;

inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    for(; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for(; isdigit(c); c = getchar()) x = x * 10 + c - 48;
    return x * f;
}

inline void addright(int x, int pos) {
    a[x].l = pos;
    a[a[pos].r].l = x;
    a[x].r = a[pos].r;
    a[pos].r = x;
}

inline void addleft(int x, int pos) {
    a[x].r = pos;
    a[a[pos].l].r = x;
    a[x].l = a[pos].l;
    a[pos].l = x;
}

inline void dele(int x) {
    if(a[x].l == -1) return;
    a[a[x].l].r = a[x].r;
    a[a[x].r].l = a[x].l;
    a[x].l = -1;
    a[x].r = -1;
}

inline void write() {
    int x = a[0].r;
    while(1) {
        cout << x << ' ';
        if(a[x].r == -1) break;
        x = a[x].r;
    }
}

int main() {
    n = read();
    int k, p;
    for(int i = 1; i <= n; i++) {
        a[i].l = a[i].r = -1;
    }
    a[1].l = 0;
    a[0].r = 1;
    for(int i = 2; i <= n; i++) {
        k = read(), p = read();
        if(p == 0) addleft(i, k);
        else addright(i, k);
    }
    m = read();
    for(int i = 1; i <= m; i++) {
        k = read();
        dele(k);
    }
    write();
    return 0;
}

posted @ 2019-06-27 16:50  Loceaner  阅读(255)  评论(0编辑  收藏  举报