试题
题目描述
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指定, 每次操作分为两步:
- 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}) Lai←reverse(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]。
- 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} 1⩽n,m⩽105
- 1 ⩽ a i , b i ⩽ n , a i ≠ b i 1 \leqslant a_i, b_i \leqslant n, a_i \neq b_i 1⩽ai,bi⩽n,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
解题思路
这是一道模拟题。要求不断地让一个列表追加到另一个列表中,并反转。但是不停反转是很耗性能的,不停地反转将会导致超时。为了解决这个反转超时问题,我们开两个表,一个正向表,一个反向。把正向表与反向表的元素对调一下,就相当于反转了。这样就不会超时了。
源代码
#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;
}