专栏文章

题解:AT_abc395_d [ABC395D] Pigeon Swap

AT_abc395_d题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@miq38735
此快照首次捕获于
2025/12/03 22:13
3 个月前
此快照最后确认于
2025/12/03 22:13
3 个月前
查看原文

题目大意

有标有 1,2,,N1, 2, \ldots, NNN 只鸽子和标有 1,2,,N1, 2, \ldots, NNN 个鸟巢。
最初,鸽子 i(1iN)i (1\leq i\leq N) 位于鸟巢 ii 中。
你将对这些鸽子执行 QQ 次操作。
有三种类型的操作:
  • 操作 11:你将得到整数 aab(1aN,1bN)b(1\leq a\leq N, 1\leq b \leq N)。将 aa 号鸽子移至 bb 号鸟巢。
  • 操作 22:你将得到整数 aab(1abN)b (1 \leq a \leq b \leq N)。将鸟巢 aa 中的所有鸽子与鸟巢 bb 中的所有鸽子交换。
  • 操作 33:你将得到一个整数 a(1aN)a(1\leq a \leq N)。输出鸽子 aa 目前所在巢穴的编号。
按操作顺序打印每个操作 33 的结果。

题解

思路

首先我们很容易想到通过一个数组 in 来记录每只鸽子所在的鸟巢,这样子对于每个操作 11,我们只需要将 in[a] 的值设为 b 即可。
但是如果只使用这么一个 in 数组,对于操作 22,我们就需要遍历每一个在 aa 巢和 bb 巢的鸽子,但对于如此大的数据,这样显然会超时。
所以我们可以考虑将他们巢的编号交换,这样就可以将时间优化到 Θ(n)\Theta(n) 了。
具体的,我们可以通过样例来看:
CPP
6 8
1 2 4
1 3 6
3 2
2 4 5
3 2
1 4 2
3 4
3 2
在这里,第 44 个操作将 44 号鸟巢和 55 号鸟巢交换。
我们将定义以下两个数组:
  • actiact_{i} 表示 ii 个存储空间记录了 actiact_{i} 号鸟巢;
  • to_actito\_act_{i}ii 号鸟巢所在的存储空间。
这么说可能有点抽象,我们结合例子来讲解:
CPP
6 2
2 4 5
2 4 6
3 6
对于这组数据:
存储空间编号112233445566
初始值123456
11 次操作(实际上对应的鸟巢编号)123546
22 次操作123645
33 次操作123645
所以最后应该输出 4,因为 66 号鸽子在鸟巢 44 里面。

11 次操作

我们需要交换 44 号巢和 55 号巢,所以现在 44 号存储空间应该存着 55 号巢。相同地,55 号存储空间存着 44 号巢:
act4=5,act5=4act_{4}=5, act_{5}=4
接下来更新 to_actto\_act 数组。现在 44 号巢被存在了 55 号存储空间,55 号巢被存在了 44 号存储空间:
to_act4=5,to_act5=4to\_act_{4}=5, to\_act_{5}=4

22 次操作

现在我们需要交换 44 号巢和 66 号巢。此时 44 号巢的数据被存在了 to_act4=5to\_act_{4}=5 号存储空间,所以我们实际上需要交换的是 55 号存储空间和 66 号存储空间。
那么这时 55 号存储空间存储的就是 66 号巢的数据,66 号存储空间存储的就是 44 号巢的数据:
actto_act4=6,actto_act6=4act_{to\_act_{4}}=6, act_{to\_act_{6}}=4
也就等同于:
act5=6,act6=4act_{5}=6, act_{6}=4
接下来,44 号巢的存储空间和 66 号巢的存储空间交换:
to_act4=6,to_act6=5to\_act_{4}=6, to\_act{6}=5

上面的过程比较绕,建议多看几遍。
所以我们就可以很轻松地得到操作 22 的代码:
CPP
scanf("%d%d",&y,&z);
act[to_act[y]]=z;
act[to_act[z]]=y;
swap(to_act[y],to_act[z]);
理解了上面的思路之后,操作 11 和操作 33 的代码就很好实现了,这里就不赘述了。

代码

CPP
#include<bits/stdc++.h>
using namespace std;
int in[1000010],act[1000010],to_act[1000010],n,q,x,y,z,tmp;
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) in[i]=act[i]=to_act[i]=i;//注意初始化
	while(q--){
		scanf("%d",&x);
		if(x==1){
			scanf("%d%d",&y,&z);
			in[y]=to_act[z];
		}else if(x==2){
			scanf("%d%d",&y,&z);
			act[to_act[y]]=z;
			act[to_act[z]]=y;
			swap(to_act[y],to_act[z]);
		}else{
			scanf("%d",&y);
			printf("%d\n",act[in[y]]);
		}
	}
    return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...