2019牛客国庆集训派对day1 第K题 双向链表练习题 解题报告

试题

试题链接

题目描述

Bobo 有 n 个列表 L 1 , L 2 , … , L n L_1, L_2, \dots, L_n L1,L2,,Ln
初始时, L i L_i Li仅包含元素 i, 即 L i = [ i ] L_i = [i] Li=[i]
他依次执行了 m 次操作。第 i 次操作由两个整数 a i a_i ai b i b_i bi指定, 每次操作分为两步:

  1. L a i ← r e v e r s e ( L a i + L b i ) L_{a_i} \leftarrow \mathrm{reverse}(L_{a_i} + L_{b_i}) Laireverse(Lai+Lbi),其中 ← \leftarrow 表示赋值,+表示列表的连接,reverse 表示列表的反转。例如, r e v e r s e ( [ 1 , 2 ] + [ 3 , 4 , 5 ] ) = [ 5 , 4 , 3 , 2 , 1 ] \mathrm{reverse}([1, 2] + [3, 4, 5]) = [5, 4, 3, 2, 1] reverse([1,2]+[3,4,5])=[5,4,3,2,1]
  2. L b i ← [ ] L_{b_i} \leftarrow [] Lbi[],其中 [] 表示空的列表。

经过 m 次操作后, 输出 L 1 L_1 L1的元素。

输入描述

输入文件包含多组数据,请处理到文件结束。
每组数据的第一行包含两个整数 n 和 m。
接下来 m 行,其中第 i 行包含 2 个整数 a i a_i ai b i b_i bi

  • 1 ⩽ n , m ⩽ 1 0 5 1 \leqslant n,m \leqslant 10^{5} 1n,m105
  • 1 ⩽ a i , b i ⩽ n , a i ≠ b i 1 \leqslant a_i, b_i \leqslant n, a_i \neq b_i 1ai,bin,ai=bi
  • n的总和,m的总和都不超过 5 × 1 0 5 5 \times 10^5 5×105

输出描述

对于每组数据,先输出 L 1 L_1 L1 的长度 ∣ L 1 ∣ |L_1| L1,再输出 ∣ L 1 ∣ |L_1| L1 个整数,表示 L 1 L_1 L1 的元素。

样例输入

2 1
1 2
2 1
2 1
3 3
3 2
3 2
1 3

样例输出

2 2 1
0
3 2 3 1

解题思路

这是一道模拟题。要求不断地让一个列表追加到另一个列表中,并反转。但是不停反转是很耗性能的,不停地反转将会导致超时。为了解决这个反转超时问题,我们开两个表,一个正向表,一个反向。把正向表与反向表的元素对调一下,就相当于反转了。这样就不会超时了。

Created with Raphaël 2.2.0 开始 建两个链表,一个正向表,一个反向表 输入追加操作 对正向表执行追加操作,即 正向表La += Lb 对反向表倒过来执行逆向追加操作,即 反向表Lb += La 把这两个表的刚变的两个元素对调一下 swap(正La, 反Lb) 把反向表的元素放到正确的位置,即 swap(反La, 反Lb) 还有下个操作吗? 输出正向表的L1元素 结束 yes no

源代码

#include <cstdio>
#include <list>
#include <algorithm>

using namespace std;

#define MAX_LENGTH 100001

int main()
{
    int n, m;
    static list<int> plist[MAX_LENGTH];
    static list<int> plist_reverse[MAX_LENGTH];
    while (scanf("%d%d", &n, &m) != EOF)
    {
        for (int i = 1; i <= n; ++i)
        {
            plist[i].clear();
            plist[i].push_back(i);

            plist_reverse[i].clear();
            plist_reverse[i].push_back(i);
        }
        while (m --)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            plist[a].splice(plist[a].end(), plist[b]);
            plist_reverse[b].splice(plist_reverse[b].end(), plist_reverse[a]);
            swap(plist[a], plist_reverse[b]);
            swap(plist_reverse[a], plist_reverse[b]);
        }
        printf("%d", (int)(plist[1].size()));
        for (int e : plist[1])
            printf(" %d", e);
        puts("");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值