P1160 队列安排

对于元素是有序号的插入删除操作,可以采用这种实现起来很简单的链表.

 

M<N<=100000

如果使用STL的链表,矛盾的地方在于它的迭代器不能随机访问,找到k号同学需要O(N),题解区有一种用数组记录迭代器的方法,看起来很繁琐.

这里采用的方法是记录1~N号节点的信息,有且仅有:

  • 该节点编号对应的同学左侧,右侧同学的编号(若没有则为0)
  • 该节点编号的同学是否存在

那么只需要设置这样的节点数组:

struct S{
    int l, r;
    bool is;    // 是否存在
}s[100010]; 

想要进行插入操作很简单,更新涉及到的两个节点的信息即可:

    if(!p){
        s[i].r = k;
        s[i].l = s[k].l;
        s[s[k].l].r = i;
        s[k].l = i;
    }else{
        s[i].r = s[k].r;
        s[i].l = k;
        s[s[k].r].l = i;
        s[k].r = i;
    }

此外,通过懒惰删除可以很轻松处理第二阶段的数据.

bool killed[100010];

此题需要注意输出格式,末尾不可有空格且需要换行.

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

struct S{
    int l, r;
    bool is;
}s[100010];
int n, m;
bool killed[100010];

int main(){
    scanf("%d", &n);
    s[1].is = true;

    for(int i = 2; i <= n; i++){
        int k, p;
        scanf("%d%d", &k, &p);
        s[i].is = true;
        if(!p){
            s[i].r = k;
            s[i].l = s[k].l;
            s[s[k].l].r = i;
            s[k].l = i;
        }else{
            s[i].r = s[k].r;
            s[i].l = k;
            s[s[k].r].l = i;
            s[k].r = i;
        }
    }

    int p;
    for(int i = 1; i <= n; i++)
        if(s[i].is && !s[i].l){
            p = i;
            break;
        }
    scanf("%d", &m);
    while(m--){
        int x;
        scanf("%d", &x);
        killed[x] = true;
    }

    bool first = true;
    while(n--){
        if(s[p].is && !killed[p]){
            if(!first) printf(" ");
            printf("%d", p);
            first = false;
        }
        p = s[p].r;
    }
    puts("");

    return 0;
}
P1160
原文地址:https://www.cnblogs.com/Gaomez/p/14350831.html