概述
You are given a permutation of the numbers 1, 2, ..., n and m pairs of positions (aj, bj).
At each step you can choose a pair from the given positions and swap the numbers in that positions. What is the lexicographically maximal permutation one can get?
Let p and q be two permutations of the numbers 1, 2, ..., n. p is lexicographically smaller than the q if a number 1 ≤ i ≤ n exists, so pk = qk for 1 ≤ k < i and pi < qi.
The first line contains two integers n and m (1 ≤ n, m ≤ 106) — the length of the permutation p and the number of pairs of positions.
The second line contains n distinct integers pi (1 ≤ pi ≤ n) — the elements of the permutation p.
Each of the last m lines contains two integers (aj, bj) (1 ≤ aj, bj ≤ n) — the pairs of positions to swap. Note that you are given a positions, not the values to swap.
Print the only line with n distinct integers p'i (1 ≤ p'i ≤ n) — the lexicographically maximal permutation one can get.
9 6 1 2 3 4 5 6 7 8 9 1 4 4 7 2 5 5 8 3 6 6 9
7 8 9 4 5 6 1 2 3
题目大意:
给你N个数,M个操作,让你给这M个操作规定一个使用顺序,使得得到的最终的序列字典序最大。
每次操作是选择某一次操作,使得两个位子上的数字进行交换。
思路:
1、考虑问题有一个递推性质,假设现在有两个操作:
x y
x z
那么显然,位子x上的数最终可以在y上也可以在z上,同理,y也可以在x上,也可以在z上,再同理,z可以在x上也可以在y上。
那么其实我们规定其操作顺序,将一个操作视为一个无向边,那么对于一个联通块中的几个位子上的数,就可以互相穿插着安排了。
2、也就是说,将一个操作看成一个无向边,对于一个联通块中的所有元素,都可以任意安排位子。
那么我们维护1e6个优先队列,s【i】中存入的元素,是表示以i为根的联通块在原序列中的位子。那么优先级我们可以定义为从大到小。
接下来我们再将元素按照值从小到大排序,那么我们每一个小的值,都从队头拿出一个最大的可以放置的位子,将这个值放置在那个位子上即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
struct node
{
int pos,val,root;
}b[1000500];
priority_queue<int,vector<int>,less<int> >s[1000500];
int a[1000500];
int f[1000500];
int ans[1000500];
int find(int a)
{
int r=a;
while(f[r]!=r)
r=f[r];
int i=a;
int j;
while(i!=r)
{
j=f[i];
f[i]=r;
i=j;
}
return r;
}
void merge(int a,int b)
{
int A,B;
A=find(a);
B=find(b);
if(A!=B)
{
f[B]=A;
}
}
int cmp(node a,node b)
{
if(a.root==b.root)
{
return a.val<b.val;
}
else return a.root<b.root;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
memset(ans,-1,sizeof(ans));
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=0;i<m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
merge(x,y);
}
int cnt=0;
for(int i=1;i<=n;i++)
{
find(i);
b[i].root=f[i];
b[i].pos=i;
b[i].val=a[i];
s[f[i]].push(i);
}
sort(b+1,b+1+n,cmp);
for(int i=1;i<=n;i++)
{
int rrr=b[i].root;
int anspos=s[rrr].top();
s[rrr].pop();
ans[anspos]=b[i].val;
}
for(int i=1;i<=n;i++)
{
printf("%d ",ans[i]);
}
printf("n");
}
}
最后
以上就是清脆海燕为你收集整理的Codeforces 691D Swaps in Permutation【并查集+优先队列+贪心】的全部内容,希望文章能够帮你解决Codeforces 691D Swaps in Permutation【并查集+优先队列+贪心】所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复