虚拟位置映射(标签鸽

有 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 基编号)。

  1. box_to_label[i]

    • 含义:巢穴 i(0 基)中当前存在的标签鸽编号(0 基)。
    • 初始化:iota 函数将其初始化为 [0,1,2,...,N-1],即初始时巢穴 i 中有标签鸽 i
  2. label_to_box[i]

    • 含义:标签鸽 i(0 基)当前所在的巢穴编号(0 基)。
    • 初始化:[0,1,2,...,N-1],即初始时标签鸽 i 在巢穴 i 中。
  3. pigeon_to_box[i]

    • 含义:真实鸽子 i(0 基)当前所在的巢穴编号(0 基)。
    • 初始化:[0,1,2,...,N-1],即初始时鸽子 i 在巢穴 i 中。

操作解析

类型 1 操作:移动鸽子 a 到巢穴 b
  • 输入:1 a ba 是鸽子编号,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 操作:交换巢穴 ab 中的所有鸽子
  • 输入:2 a bab 是巢穴编号,均为 1 基)。
  • 逻辑:无需移动真实鸽子,只需交换标签鸽 ab 的位置,即可等效于交换两个巢穴的所有鸽子。代码中分为两步:
    1. 交换标签鸽 ab 所在的巢穴:

      复制代码
      swap(label_to_box[a-1], label_to_box[b-1]);  // 标签鸽 a 和 b 的位置互换
    2. 同步更新巢穴中对应的标签鸽(维护 box_to_labellabel_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 aa 是鸽子编号,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;

    }

相关推荐
橘颂TA14 分钟前
【剑斩OFFER】算法的暴力美学——只出现一次的数字 ||
算法·leetcode·动态规划
码力码力我爱你1 小时前
Harmony OS C++实战
开发语言·c++
大白的编程日记.1 小时前
【计算网络学习笔记】MySql的多版本控制MVCC和Read View
网络·笔记·学习·mysql
Vect__1 小时前
别再只懂 C++98!C++11 这7个核心特性,直接拉开你与普通开发者的差距
c++
想唱rap1 小时前
C++ map和set
linux·运维·服务器·开发语言·c++·算法
IMPYLH2 小时前
Lua 的 require 函数
java·开发语言·笔记·后端·junit·lua
小欣加油2 小时前
leetcode 1018 可被5整除的二进制前缀
数据结构·c++·算法·leetcode·职场和发展
无敌最俊朗@3 小时前
链表-力扣hot100-随机链表的复制138
数据结构·leetcode·链表
WWZZ20253 小时前
快速上手大模型:深度学习12(目标检测、语义分割、序列模型)
深度学习·算法·目标检测·计算机视觉·机器人·大模型·具身智能