[luogu p1160] 队列安排

传送门

题面

题目描述

一个学校里老师要将班上\(N\)个同学排成一列,同学被编号为\(1\sim N\),他采取如下的方法:

  1. 先将\(1\)号同学安排进队列,这时队列中只有他一个人;
  2. \(2-N\)号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为\(1\sim (i -1)\)中某位同学(即之前已经入列的同学)的左边或右边;
  3. 从队列中去掉\(M(M<N)\)个同学,其他同学位置顺序不变。

在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。

输入输出格式

输入格式

第\(1\)行为一个正整数\(N\),表示了有\(N\)个同学。

第\(2-N\)行,第\(i\)行包含两个整数\(k,p\),其中\(k\)为小于\(i\)的正整数,\(p\)为\(0\)或者\(1\)。若\(p\)为\(0\),则表示将\(i\)号同学插入到\(k\)号同学的左边,\(p\)为\(1\)则表示插入到右边。

第\(N+1\)行为一个正整数\(M\),表示去掉的同学数目。

接下来\(M\)行,每行一个正整数\(x\),表示将\(x\)号同学从队列中移去,如果\(x\)号同学已经不在队列中则忽略这一条指令。

输出格式

\(1\)行,包含最多\(N\)个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。

输入输出样例

输入样例 #1

4
1 0
2 1
1 0
2
3
3

输出样例 #1

2 4 1

说明

样例解释: 将同学\(2\)插入至同学\(1\)左边,此时队列为:
\(2 1\)
将同学\(3\)插入至同学\(2\)右边,此时队列为:
\(2 3 1\)
将同学\(4\)插入至同学\(1\)左边,此时队列为:
\(2 3 4 1\)
将同学\(3\)从队列中移出,此时队列为: \(2 4 1\)
同学\(3\)已经不在队列中,忽略最后一条指令
最终队列:
\(2 4 1\)

数据范围

对于\(20\%\)的数据,有\(N≤10\);
对于\(40\%\)的数据,有\(N≤1000\);
对于\(100\%\)的数据,有\(N, M≤100000\)。

分析

这道题啊,赤裸裸的链表。我们直接实现一个双向链表就好了。这里使用数组实现双向链表。

我们先定义一个node节点:

struct node {
    int l, r;
}l[100005];

然后初始化这个链表。

void InitList(int n) {
    for(int i = 1; i <= n; i++)
        l[i].l = l[i].r = -1;//全部初始化为-1
    l[0].r = 1;//因为一开始就有编号为1的同学
    l[1].l = 0;
    return ;
}

可以看到,我们把下标为0作为双向链表的开始。这可以避免一些问题。
接下来定义addLeft函数,在pos位置的左边添加数x。这就是双向链表的板子了,具体见注释。

void addLeft(int x, int pos) {
    l[x].r = pos;//节点x的右边设为pos
    l[x].l = l[pos].l;//节点x的左边是pos位置节点的左边节点
    l[l[pos].l].r = x;//pos的左边节点的右边节点应该是x
    l[pos].l = x;//pos的左边是x
    return ;
}

addRight函数同理。

void addRight(int x, int pos) {
    l[x].l = pos;
    l[x].r = l[pos].r;
    l[l[pos].r].l = x;
    l[pos].r = x;
    return ;
}

那么怎么删除呢?很简单,我们将要删除的节点x的两边都设为-1,然后原来两边的节点中,左边的和右边的跳过节点x直接link together

void DeleteNode(int x) {
    if(l[x].l != -1) {
        l[l[x].l].r = l[x].r;
        l[l[x].r].l = l[x].l;
        //Link together
        l[x].l = -1;
        l[x].r = -1;
        //delete node x
    }
    return ;
}

最后是遍历。由于我们是从下标为0开始的,从0开始遍历当前节点的右节点就好了,一直到-1

void printList() {
    int x = l[0].r;
    printf("%d ",x);
    while(l[x].r != -1) {
        x = l[x].r;
        printf("%d ", x);
    }
    return ;
}

完整代码如下:

代码

/*
 * @Author: crab-in-the-northeast
 * @Date: 2020-03-07 10:37:45
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2020-03-07 12:16:14
 */
#include <iostream>
#include <cstdio>

struct node {
    int l, r;
}l[100005];

void InitList(int n) {
    for(int i = 1; i <= n; i++)
        l[i].l = l[i].r = -1;
    l[0].r = 1;
    l[1].l = 0;
    return ;
}

void addLeft(int x, int pos) {
    l[x].r = pos;
    l[x].l = l[pos].l;
    l[l[pos].l].r = x;
    l[pos].l = x;
    return ;
}

void addRight(int x, int pos) {
    l[x].l = pos;
    l[x].r = l[pos].r;
    l[l[pos].r].l = x;
    l[pos].r = x;
    return ;
}

void DeleteNode(int x) {
    if(l[x].l != -1) {
        l[l[x].l].r = l[x].r;
        l[l[x].r].l = l[x].l;
        l[x].l = -1;
        l[x].r = -1;
    }
    return ;
}

void printList() {
    int x = l[0].r;
    printf("%d ",x);
    while(l[x].r != -1) {
        x = l[x].r;
        printf("%d ", x);
    }
    return ;
}

int main() {
    int n;
    scanf("%d",&n);
    InitList(n);

    for(int i = 2; i <= n; i++) {
        int pos, dir;
        scanf("%d %d",&pos, &dir);
        if(dir) addRight(i, pos);
        else addLeft(i, pos);
    }

    int m;
    scanf("%d",&m);
    for(int i = 1; i <= m; i++) {
        int x;
        scanf("%d",&x);
        DeleteNode(x);
    }
    printList();
    return 0;
}

评测结果

AC 100R31453533

原文地址:https://www.cnblogs.com/crab-in-the-northeast/p/luogu-p1160.html

时间: 2024-08-26 07:37:06

[luogu p1160] 队列安排的相关文章

洛谷P1160 队列安排 链表

洛谷P1160 队列安排   链表 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <string> 6 #include <algorithm> 7 #include <iomanip> 8 #include <iostream> 9 using namespace std

洛谷 P1160 队列安排 Label:链表 不会

题目描述 一个学校里老师要将班上N个同学排成一列,同学被编号为1-N,他采取如下的方法: 1.先将1号同学安排进队列,这时队列中只有他一个人: 2.2-N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1-i -1中某位同学(即之前已经入列的同学)的左边或右边: 3.从队列中去掉M(M<N)个同学,其他同学位置顺序不变. 在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号. 输入输出格式 输入格式: 输入文件arrange.in的第1行为一个正整数N

洛谷 P1160 队列安排

题目描述 一个学校里老师要将班上N个同学排成一列,同学被编号为1-N,他采取如下的方法: 1.先将1号同学安排进队列,这时队列中只有他一个人: 2.2-N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1-i -1中某位同学(即之前已经入列的同学)的左边或右边: 3.从队列中去掉M(M<N)个同学,其他同学位置顺序不变. 在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号. 输入输出格式 输入格式: 输入文件arrange.in的第1行为一个正整数N

P1160 队列安排

题目描述 一个学校里老师要将班上N个同学排成一列,同学被编号为1-N,他采取如下的方法: 1.先将1号同学安排进队列,这时队列中只有他一个人: 2.2-N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1-i -1中某位同学(即之前已经入列的同学)的左边或右边: 3.从队列中去掉M(M<N)个同学,其他同学位置顺序不变. 在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号. 输入输出格式 输入格式: 输入文件arrange.in的第1行为一个正整数N

洛谷P1160 队列安排

题目描述 一个学校里老师要将班上N个同学排成一列,同学被编号为1-N,他采取如下的方法: 1.先将1号同学安排进队列,这时队列中只有他一个人: 2.2-N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1-i -1中某位同学(即之前已经入列的同学)的左边或右边: 3.从队列中去掉M(M<N)个同学,其他同学位置顺序不变. 在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号. 输入输出格式 输入格式: 输入文件arrange.in的第1行为一个正整数N

luoguP1160 队列安排 x

P1160 队列安排 982通过 2.3K提交 题目提供者 该用户不存在 标签 云端 难度 普及/提高- 时空限制 1s / 128MB 题目描述 一个学校里老师要将班上N个同学排成一列,同学被编号为1-N,他采取如下的方法: 1.先将1号同学安排进队列,这时队列中只有他一个人: 2.2-N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1-i -1中某位同学(即之前已经入列的同学)的左边或右边: 3.从队列中去掉M(M<N)个同学,其他同学位置顺序不变. 在所有同学按

解题报告:luogu P1160

题目链接:P1160 队列安排 链表板子题,但是过于垃圾的我不会指针,好在可以用数组去模拟链表,然后果然一发过了. 不要忘了更新有关元素就好. \(Code\): #include<iostream> #include<cstdio> #include<cmath> using namespace std; //模板题就先不尛了 #define MAXN 1000005 struct node { int l,r; }a[MAXN]; #define read(x) s

luogu1160 队列安排

https://www.luogu.org/problemnew/show/1160 题目描述 一个学校里老师要将班上N个同学排成一列,同学被编号为1-N,他采取如下的方法: 1.先将1号同学安排进队列,这时队列中只有他一个人: 2.2-N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1-i -1中某位同学(即之前已经入列的同学)的左边或右边: 3.从队列中去掉M(M<N)个同学,其他同学位置顺序不变. 在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学

P2837 晚餐队列安排

题目背景 Usaco Feb08 Bronze 题目描述 为了避免餐厅过分拥挤,FJ要求奶牛们分2批就餐.每天晚饭前,奶牛们都会在餐厅前排队入内,按FJ的设想,所有第2批就餐的奶牛排在队尾,队伍的前半部分则由设定为第1批就餐的奶牛占据.由于奶牛们不理解FJ的安排,晚饭前的排队成了一个大麻烦. 第i头奶牛有一张标明她用餐批次D_i(1 <= D_i <= 2)的卡片.虽然所有N头奶牛排成了很整齐的队伍,但谁都看得出来,卡片上的号码是完全杂乱无章的. 在若干次混乱的重新排队后,FJ找到了一种简单些