题目大意:
AngryBacon 非常喜欢序列,与序列有关的一切都喜欢。
AngryBacon 面前摆着一个长度为 N 的序列,每个元素为不超过 M 的正整数。
AngryBacon 会使用 Q 次魔法,每次魔法的内容为一对不超过 M 的正整数 a,b,表示将序列中所有为a的数改写为b。
AngryBacon 想知道在最后他心爱的序列变成了什么样。
输入:
第一行,包含三个整数 N,M,Q,意义如上所述。
第二行,包含n个整数表示初始序列。接下来Q行,每行2个整数a,b。
输出:
输出一行,包含 N 个整数,表示最后序列的形态。
样例输入:
5 5 3
1 2 3 4 5
3 1
4 3
1 5
样例输出:
5 2 5 3 5
数据范围:
对于20%的数据:1≤n,m,Q≤1000。
对于100的数据:1≤n,m,Q≤1000000,1≤a,b,Ai≤M。
思路1:
首先应该要想到用并查集这个数据结构来解决这个问题,因为并查集可以把具有相同特点的节点连接到一棵树上,在本题中,每一个操作就是把a变成b,也就是通过找到一个东西将数列中为a的数与为b的数联系起来
可以试试通过他们的位置将他们联系起来
首先正向考虑,发现样例就不符合我们的想法,第一步数列中为3的位置上都指向了1的位置,第二步应该数列中为4的位置指向为3的位置,根据并查集的性质,它会由于第一步的结果指向1的位置,达不到我们想要的结果。。。
如果是反向考虑的话,和正向差不多,某些不应该联系起来的数据还会联系起来,那我们考虑一下只用一个根数组,反向遍历q个要求的话,它就会避免这个错误,那就用样例反向模拟一下,首先1指向5,再4指向3,再3指向1,从而间接地达到3指向5的目的,但是不会造成4指向1的错误,刚刚好
开始的时候每个数值的根就是自己的下标,一一对应并且数值等于根
Code:
#include<bits/stdc++.h>
#include<map>
using namespace std;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int,int> PII;
typedef long long ll;
int n,m,ans;
int a[maxn],root[maxn];
PII p[maxn];
int Find(int x){
return root[x];
}
int main(){
int q;scanf("%d%d%d",&n,&m,&q);
for(int i = 1;i <= n;i ++) root[i] = i;
for(int i = 1;i <= n;i ++)
scanf("%d",&a[i]);
for(int i = 1;i <= q;i ++)
scanf("%d%d",&p[i].first,&p[i].second);
for(int i = q;i >= 1;i --)
root[p[i].first] = Find(p[i].second);
for(int i = 1;i <= n;i ++)
printf("%d ",Find(a[i]));
return 0;
}
思路2:
那这个题能不能真正的用并查集做呢,答案当然是可以的了
为了避免思路一中的错误,我们需要加点操作,还是拿样例来说,当3的位置指向1的位置后,怎样才能保证4的位置指向3的位置而不会间接的指向到1的位置
我们可以另开一个数组记录每个数指向的位置,当3的位置指向1的位置时,我们可以把vis[3]清0,就表示该数列中没有3这个数了
当然过程中还要注意一些细节操作,比如将a改为b时,如果a不存在,那就直接continue;如果存在,首先将vis[a]清0,然后判断b是否存在,如果b存在,让a的位置指向b的位置,否则就让vis[b]=a指向的位置,再将原数组中a所在的位置改为b就好啦
code:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<map>
using namespace std;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int,int> PII;
typedef long long ll;
int n,m,q;
int a[maxn];
int pre[maxn];
int vis[maxn];
void read(int &x){
char ch = getchar(); x = 0;
for (; ch < '0' || ch > '9'; ch = getchar());
for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
}
int Find(int x){
if(x == pre[x]) return pre[x];
else return pre[x] = Find(pre[x]);
}
int main(){
read(n);read(m);read(q);
for(int i = 1;i <= n;i ++) pre[i] = i;
for(int i = 1;i <= n;i ++){
read(a[i]);
if(!vis[a[i]]){
vis[a[i]] = i;
}
else pre[i] = vis[a[i]];
}
while(q --){
int x,y;scanf("%d%d",&x,&y);
int temp = vis[x];
if(temp){
vis[x] = 0;
if(vis[y]) pre[Find(temp)] = Find(vis[y]);
else vis[y] = temp,a[temp] = y;
}
}
for(int i = 1;i <= n;i ++)
printf("%d ",a[Find(i)]);
return 0;
}
只有耐得住寂寞,才能经得起辉煌!