CF691D 题解
题目分析
随机跳到的一道很有意思的题。
显然在这 \(m\) 对交换中,我们可以将它们划为多个集合,其中所有的数都是可以互相交换的。
那么如何去划分这些集合?没错,并查集。把可以互换的数当成点并连边,接着就可以并查集找连通块。
已经满足了一个条件,接着我们去找连通块中字典序最大的排列。显然在集合中再进行一次由大到小的排序就可以了。对于这一步,所有并查集题解似乎都不约而同用了滚动数组,但是使用优先队列会更加简单,不需要自己进行额外的排序。
贴上代码
#include<bits/stdc++.h>
// #define int long long
#define debug puts("Shiina_Mashiro_kawaii")
#define ok puts("Yes")
#define no puts("No")
using namespace std;
int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-48;
c=getchar();
}
return x*f;
}
const int maxn=1e6+5;
int n,m;
int a[maxn];
int f[maxn];
priority_queue<int> q[maxn];
// int cnt_edge,head[maxn];
// struct edge{
// int to,nxt;
// }e[maxn<<1];
// void add(int u,int v){
// e[++cnt_edge].nxt=head[u];
// e[cnt_edge].to=v;
// head[u]=cnt_edge;
// }
int find(int x){
if(x!=f[x]) f[x]=find(f[x]);
return f[x];
}
void unity(int x,int y){f[find(x)]=find(y);}
inline void init(){
n=read();m=read();
for(register int i=1;i<=n;++i) f[i]=i;
for(register int i=1;i<=n;++i) a[i]=read();
while(m--){
int u=read(),v=read();
unity(u,v);
}
}
int main(){
init();
for(register int i=1;i<=n;++i) q[find(i)].push(a[i]);
for(register int i=1;i<=n;++i){
int fi=find(i);
printf("%d ",q[fi].top());q[fi].pop();
}
}

浙公网安备 33010602011771号