codeforces-1131F-Asya And Kittens(并查集)

题意:n个数字给n-1对x,y;每次有x的块和有y的块合并且这两个块相邻。输出一个刚开始的序列时能合并完。

题解一:并查集加vector对于并查集的每个集合保存在一个vector里面,模拟即可。
但是需要注意2点:
1.使用vector().swap( vt );来清空vector vt。
2.在将一个vector压入另外一个vector 时将小的压入大的不然就交换一下2个vector再压入。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 150005;
int f[maxn];

int _find(int k)
{
    if(k != f[k]) f[k] = _find(f[k]);
    return f[k];
}
vector<int> son[maxn];
int main()
{
//    freopen("in.txt", "r", stdin);
    int ans[maxn]; int len = 0;
    int n; scanf("%d",&n);
    for(int i = 1; i <= n; i++)
    {
        f[i] = i;
        son[i].push_back(i);
    }
    int fir; n--; int a; int b;

    while(n--)
    {
        scanf("%d%d",&a,&b);
        int x = _find(a);
        int y = _find(b);

        if(y == fir||(x!=fir&&y!=fir&&son[y].size()>son[x].size()))//将小的压入大的否则交换。
        {
            f[x] = y;
            swap(x, y);
        }
        else
            f[y] = x;
        if(x != fir)
        {
            int lenn = son[y].size();
            for(int i = 0; i < lenn; i++) son[x].push_back(son[y][i]);
            vector<int>().swap(son[y]);//清空内存防止爆炸。
        }


        if(len == 0)
        {
            fir = x;
            int lenn = son[x].size();
            for(int i = 0; i < lenn; i++)
                ans[len++] = son[x][i];
            vector<int>().swap(son[x]);
        }
        else if(x == fir)
        {
            int lenn = son[y].size();
            for(int i = 0; i < lenn; i++)
                ans[len++] = son[y][i];
            vector<int>().swap(son[y]);
        }
    }

    for(int i = 0; i < len; i++)
        printf("%d ",ans[i]);
    return 0;
}

题解2:
直接用2个数组保存每个元素所在集合的头和尾;具体思路和题解1一样。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int f[maxn];

int _find(int k)
{
    if(k != f[k])
        f[k] = _find(f[k]);
    return f[k];
}
int son[maxn]; int lenn[maxn]; int wei[maxn];
int main()
{
//    freopen("in.txt", "r", stdin);
    int ans[maxn]; int len = 0;
    int n; scanf("%d", &n);
    for(int i = 1; i <= n; i++)
    {
        f[i] = i;
        son[i] = i;
        lenn[i] = 1;
        wei[i] = i;
    }
    int fir; n--; int a; int b;
    memset(ans, 0, sizeof(ans));
    while(n--)
    {
        scanf("%d%d", &a, &b);
        int x = _find(a);
        int y = _find(b);

        if(y == fir)
        {
            f[x] = y;
            swap(x, y);
        }
        else
            f[y] = x;

        if(x != fir)
        {
            son[wei[x]] = y;
            lenn[x] += lenn[y];
            wei[x] = wei[y];
        }
        if(len == 0)
        {
            fir = x;
            for(int i = x, j = 0; j < lenn[x]; i = son[x], j++)
                ans[len++] = i;
        }
        else if(x == fir)
        {
            for(int i = 0, j = y; i < lenn[y]; i++, j = son[j])
                ans[len++] = j;
        }

    }

    for(int i = 0; i < len; i++)
        printf("%d ", ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值