zoukankan      html  css  js  c++  java
  • [luogu p1160] 队列安排

    传送门

    题面

    题目描述

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

    1. 先将(1)号同学安排进队列,这时队列中只有他一个人;
    2. (2-N)号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为(1sim (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

  • 相关阅读:
    maven 笔记
    面试题53:在排序数组中查找数字
    面试题52:两个链表的第一个公共节点
    面试题51:数组中的逆序对
    面试题50_2:字符流中第一个只出现一次的字符
    面试题50:第一个只出现一次的字符
    面试题49:丑数
    面试题48:最长不含重复字符的连续子字符串
    面试题47:礼物的最大值
    面试题8:二叉树的下一个节点
  • 原文地址:https://www.cnblogs.com/crab-in-the-northeast/p/luogu-p1160.html
Copyright © 2011-2022 走看看