#做题有感——并查集

分析

交换对将序列分为(1,4,7)(2,5,8)(3,6,9)。所有数字只能在自己的“队伍”中移动,为了获得最大字典序,贪心将最大的数字放在前面输出即可。

问题即为:如何将数字分组,并输出最大数字?

解决

数据结构:大根堆,方便最后输出和弹出最大元素。

分组:利用并查集创建以每个father为代表的队伍,并将队伍放进大根堆。(大根堆以father为标识)。

#include<bits/stdc++.h> 

using namespace std;
const int N = 2e5+7;
int n ,m , num[N],fa[N];
priority_queue<int> q[N];
int find(int x){
    return x==fa[x] ? x:(fa[x]=find(fa[x]));//fa是自己说明没有fa,返回
}
void merge(int i ,int j){ //合并,即统一fa
    int x=find(i),y=find(j);
    if(x!=y)
    fa[x]=y;
}
int main( )
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>num[i];
        fa[i]=i;//fa都是自己
    }
    for(int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        merge(x,y);//合并fa
    }
    for(int i=1;i<=n;i++)
    q[find(i)].push(num[i]); //找到fa,每个fa为标识,创建大根堆
    for(int i =1;i<=n;i++){
        int a=find(i);//当前位置统一的fa
        cout<<q[a].top()<<" ";//fa大根堆中最大的
        q[a].pop();
    }
    //1 4 7 |2 5 8
    //fa分别是1和2,代表两个大根堆
    //如果遇到某一个位置找到fa是1,说明是1 4 7,那就把最大的输出(即尽可能把大的往前放

    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值