题解:AT_abc395_d [ABC395D] Pigeon Swap
Hero_Broom · · 题解
AT_abc395_d [ABC395D] Pigeon Swap 题目链接
题目大意
有标有
最初,鸽子
你将对这些鸽子执行
有三种类型的操作:
-
操作
1 :你将得到整数a 和b(1\leq a\leq N, 1\leq b \leq N) 。将a 号鸽子移至b 号鸟巢。 -
操作
2 :你将得到整数a 和b (1 \leq a \leq b \leq N) 。将鸟巢a 中的所有鸽子与鸟巢b 中的所有鸽子交换。 -
操作
3 :你将得到一个整数a(1\leq a \leq N) 。输出鸽子a 目前所在巢穴的编号。
按操作顺序打印每个操作
题解
思路
首先我们很容易想到通过一个数组 in 来记录每只鸽子所在的鸟巢,这样子对于每个操作 in[a] 的值设为 b 即可。
但是如果只使用这么一个 in 数组,对于操作
所以我们可以考虑将他们巢的编号交换,这样就可以将时间优化到
具体的,我们可以通过样例来看:
6 8
1 2 4
1 3 6
3 2
2 4 5
3 2
1 4 2
3 4
3 2
在这里,第
我们将定义以下两个数组:
这么说可能有点抽象,我们结合例子来讲解:
6 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,因为
第 1 次操作
我们需要交换
接下来更新
第 2 次操作
现在我们需要交换
那么这时
也就等同于:
接下来,
上面的过程比较绕,建议多看几遍。
所以我们就可以很轻松地得到操作
scanf("%d%d",&y,&z);
act[to_act[y]]=z;
act[to_act[z]]=y;
swap(to_act[y],to_act[z]);
理解了上面的思路之后,操作
代码
#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;
}