虚拟位置映射(标签鸽
有 N 只鸽子,标号为 1, 2, …, N,和 N 个巢穴,标号为 1, 2, …, N。
初始时,鸽子 i(1≤i≤N)在巢穴 i 中。
你将对这些鸽子执行 Q 次操作。
操作有三种类型:
类型 1:给定整数 a 和 b(1≤a≤N,1≤b≤N)。将鸽子 a 从当前所在的巢穴中取出,移到巢穴 b 中。类型 2:给定整数 a 和 b(1≤a<b≤N)。将巢穴 a 中的所有鸽子移到巢穴 b 中,同时将巢穴 b 中的所有鸽子移到巢穴 a 中。这两个移动是同时进行的。类型 3:给定整数 a(1≤a≤N)。鸽子 a 报告它当前所在的巢穴标号。
按类型 3 操作给出的顺序,输出每个类型 3 操作的结果。
如果尝试用朴素的方式维护诸如 p2b [i] :=(鸽子 i 当前所在的巢穴编号)这样的信息,那么第二种类型的操作就需要对许多鸽子执行操作,因此很难在时间限制内完成。
相反,我们可以考虑引入虚拟的 “标签鸽”
核心思路
通过三个数组维护鸽子、标签鸽、巢穴之间的映射关系,避免了类型 2 操作中 “移动所有鸽子” 的耗时操作。
- 标签鸽:虚拟的 “标记物”,用于间接表示巢穴的逻辑关系,交换标签鸽即可等效于交换两个巢穴的所有鸽子(但无需实际移动)。
- 映射关系:用三个数组记录位置映射,通过更新映射而非实际移动元素来处理操作。
数组定义与初始化
假设巢穴、鸽子、标签鸽的编号均为 1~N(代码中用 0~N-1 存储,最后加 1 转换为 1 基编号)。
-
box_to_label[i]- 含义:巢穴
i(0 基)中当前存在的标签鸽编号(0 基)。 - 初始化:
iota函数将其初始化为[0,1,2,...,N-1],即初始时巢穴i中有标签鸽i。
- 含义:巢穴
-
label_to_box[i]- 含义:标签鸽
i(0 基)当前所在的巢穴编号(0 基)。 - 初始化:
[0,1,2,...,N-1],即初始时标签鸽i在巢穴i中。
- 含义:标签鸽
-
pigeon_to_box[i]- 含义:真实鸽子
i(0 基)当前所在的巢穴编号(0 基)。 - 初始化:
[0,1,2,...,N-1],即初始时鸽子i在巢穴i中。
- 含义:真实鸽子
操作解析
类型 1 操作:移动鸽子 a 到巢穴 b
- 输入:
1 a b(a是鸽子编号,b是目标巢穴编号,均为 1 基)。 - 逻辑:鸽子
a需要移动到 “标签鸽b所在的巢穴”(因为标签鸽b代表巢穴b的逻辑位置)。代码中:
即更新鸽子pigeon_to_box[a-1] = label_to_box[b-1]; // a-1 转换为 0 基鸽子编号,b-1 转换为 0 基标签鸽编号a的位置为标签鸽b所在的巢穴。
类型 2 操作:交换巢穴 a 和 b 中的所有鸽子
- 输入:
2 a b(a和b是巢穴编号,均为 1 基)。 - 逻辑:无需移动真实鸽子,只需交换标签鸽
a和b的位置,即可等效于交换两个巢穴的所有鸽子。代码中分为两步:- 交换标签鸽
a和b所在的巢穴:swap(label_to_box[a-1], label_to_box[b-1]); // 标签鸽 a 和 b 的位置互换 - 同步更新巢穴中对应的标签鸽(维护
box_to_label和label_to_box的一致性):
此时,swap(box_to_label[label_to_box[a-1]], box_to_label[label_to_box[b-1]]);label_to_box[a-1]是交换后标签鸽a所在的巢穴,label_to_box[b-1]是交换后标签鸽b所在的巢穴。交换这两个巢穴对应的标签鸽,确保box_to_label正确记录 “巢穴→标签鸽” 的映射。
- 交换标签鸽
类型 3 操作:查询鸽子 a 所在的巢穴编号
- 输入:
3 a(a是鸽子编号,1 基)。 - 逻辑:鸽子
a所在的巢穴中,当前的标签鸽编号即为该巢穴的逻辑编号(因为标签鸽代表巢穴的标识)。代码中:// 1. 找到鸽子 a 所在的巢穴:pigeon_to_box[a-1](0 基) // 2. 找到该巢穴中当前的标签鸽:box_to_label[巢穴编号](0 基) // 3. 转换为 1 基编号输出 cout << box_to_label[pigeon_to_box[a-1]] + 1 << '\n';
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int N, Q;cin >> N >> Q;vector<int> b2l(N), l2b(N), p2b(N);iota(begin(b2l), end(b2l), 0);iota(begin(l2b), end(l2b), 0);iota(begin(p2b), end(p2b), 0);while (Q--) {int t, a, b;cin >> t;if (t == 1) {cin >> a >> b;p2b[a-1] = l2b[b-1];} else if (t == 2) {cin >> a >> b;swap(l2b[a-1], l2b[b-1]);swap(b2l[l2b[a-1]], b2l[l2b[b-1]]);} else {cin >> a;cout << b2l[p2b[a-1]] + 1 << '\n';}}return 0;
}