AngryBacon 非常喜欢序列,与序列有关的一切都喜欢。
AngryBacon 面前摆着一个长度为 N 的序列,每个元素为不超过 M 的正整数。
AngryBacon 会使用 Q 次魔法,每次魔法的内容为一对不超过 M 的正整数 a,b,表示将序列中所有 为 a 的数改写为 b。
AngryBacon 想知道在最后他心爱的序列变成了什么样。
Input
第一行,包含三个整数 N,M,Q,意义如上所述。
第二行,包含n个整数表示初始序列。接下来Q行,每行2个整数a,b。
Output
输出一行,包含 N 个整数,表示最后序列的形态。
Samples
Input Copy
5 5 3
1 2 3 4 5
3 1
4 3
1 5
Output
5 2 5 3 5
Hint
【数据范围】
对于20%的数据:1≤n,m,Q≤1000。
对于100的数据:1≤n,m,Q≤1000000,1≤a,b,Ai≤M。
Source
石光中学 2017长乐暑期集训第7套
题意: 应该可以看懂。
题解: 不难想到用并查集,难想到的是每次得用一个新的替换
就像这样
1->2
2->3
5->1
这样就不容易区分1是新生成的还是原本的
所以我们需要一个新数组来维护。
///a[x]=i 表示x这个数出现最早点在i
他其实每次一个数换成另一个数,是属于那种牵一动而动全身,然而我们如果动全身时间复杂度会很大,所以我们就找出一个代表,只用这一个代表来表示这一类数,如果这类数变了这把这一个数变一下就行了。
其实就是维护那个数出现最早的位置,每次替换,就把它最前面那一个换掉就行了。
用快读吧,我用scanf超时了。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e6+7;
int dis[maxn],vis[maxn];
int a[maxn];
int f(int x){
if(dis[x]==x) return x;
return dis[x]=f(dis[x]);
}
int read()
{
int ret=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9') {
if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
int main(){
int n,m,p;
n=read();m=read();p=read();
///scanf("%lld%lld%lld",&n,&m,&p);
for(int i=1;i<=n;i++) dis[i]=i;
for(int i=1;i<=n;i++){
int x;
x=read();
///a[x]=i 表示x这个数出现最早点在i
///vis[i]=x 表示i点上放的是x
if(!a[x]) a[x]=i,vis[i]=x;///没动过 找到第一个节点
else dis[i]=f(a[x]);
///找到第一次出现的位置
}
while(p--){
int x,y;
x=read();y=read();
///找到第一次出现的地方
if(a[x]){
int tmp=a[x];
a[x]=0;
///找的这个,因为全部替换这个数就不会存在在序列中清零
///存在,就比较最靠前的是替换的靠前还是原本的,把他们连起来
if(a[y])dis[f(tmp)]=f(a[y]);
else a[y]=tmp,vis[tmp]=y;
///不存在b直接把a换成b不用比较 那么s数组放的值也会变化
}
}
for(int i=1;i<=n;i++){
printf("%d ",vis[f(i)]);///最后一次变成了什么
}
return 0;
}