专栏文章
题解: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 个月前
题目大意
有标有 的 只鸽子和标有 的 个鸟巢。
最初,鸽子 位于鸟巢 中。
你将对这些鸽子执行 次操作。
有三种类型的操作:
-
操作 :你将得到整数 和 。将 号鸽子移至 号鸟巢。
-
操作 :你将得到整数 和 。将鸟巢 中的所有鸽子与鸟巢 中的所有鸽子交换。
-
操作 :你将得到一个整数 。输出鸽子 目前所在巢穴的编号。
按操作顺序打印每个操作 的结果。
题解
思路
首先我们很容易想到通过一个数组
in 来记录每只鸽子所在的鸟巢,这样子对于每个操作 ,我们只需要将 in[a] 的值设为 b 即可。但是如果只使用这么一个
in 数组,对于操作 ,我们就需要遍历每一个在 巢和 巢的鸽子,但对于如此大的数据,这样显然会超时。所以我们可以考虑将他们巢的编号交换,这样就可以将时间优化到 了。
具体的,我们可以通过样例来看:
CPP6 8
1 2 4
1 3 6
3 2
2 4 5
3 2
1 4 2
3 4
3 2
在这里,第 个操作将 号鸟巢和 号鸟巢交换。
我们将定义以下两个数组:
-
表示 个存储空间记录了 号鸟巢;
-
表 号鸟巢所在的存储空间。
这么说可能有点抽象,我们结合例子来讲解:
CPP6 2
2 4 5
2 4 6
3 6
对于这组数据:
| 存储空间编号 | ||||||
|---|---|---|---|---|---|---|
| 初始值 | 1 | 2 | 3 | 4 | 5 | 6 |
| 第 次操作(实际上对应的鸟巢编号) | 1 | 2 | 3 | 5 | 4 | 6 |
| 第 次操作 | 1 | 2 | 3 | 6 | 4 | 5 |
| 第 次操作 | 1 | 2 | 3 | 6 | 4 | 5 |
所以最后应该输出
4,因为 号鸽子在鸟巢 里面。第 次操作
我们需要交换 号巢和 号巢,所以现在 号存储空间应该存着 号巢。相同地, 号存储空间存着 号巢:
接下来更新 数组。现在 号巢被存在了 号存储空间, 号巢被存在了 号存储空间:
第 次操作
现在我们需要交换 号巢和 号巢。此时 号巢的数据被存在了 号存储空间,所以我们实际上需要交换的是 号存储空间和 号存储空间。
那么这时 号存储空间存储的就是 号巢的数据, 号存储空间存储的就是 号巢的数据:
也就等同于:
接下来, 号巢的存储空间和 号巢的存储空间交换:
上面的过程比较绕,建议多看几遍。
所以我们就可以很轻松地得到操作 的代码:
CPPscanf("%d%d",&y,&z);
act[to_act[y]]=z;
act[to_act[z]]=y;
swap(to_act[y],to_act[z]);
理解了上面的思路之后,操作 和操作 的代码就很好实现了,这里就不赘述了。
代码
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 条评论,欢迎与作者交流。
正在加载评论...