2020牛客暑假多校第三场补题

比赛链接:link


   

G STL中list的使用

   题意是说对于一张图有 n n n 个点, m m m 条边,一开始每个点自为一个 g r o u p group group,我们现在有 q q q 次操作,每次操作选定 g r o u p group group 的编号为 o i o_i oi,若是 o i o_i oi 组没有点,则不发生变化,否则与 o i o_i oi 组的点相连的点若是属于其他组 o j o_j oj,则 o j o_j oj 组的点并入 o i o_i oi o j o_j oj 变空。全部操作之后输出每个点属于那一组。有多组输入, n , m , q ≤ 5 e 8 n, m, q ≤ 5e8 n,m,q5e8
   经过分析我们发现,若是 o i o_i oi 组在一轮操作中被并掉,那么 o i o_i oi 组就一直为空;若是一个点在一次操作中和另一个点处于同一组,那么之后它们永远属于同一组。于是自然想到用并查集记录每个 g r o u p group group 的元素,并记录与每个 g r o u p group group 相连的点。
   一开始想到用 v e c t o r vector vector 记录,但是这样的话一个 g r o u p group group 被并入另一个 g r o u p group group 时,它所记录的相连的点也要相应复制到另一个 g r o u p group group,这样就会进行很多次复制。查看别人的题解发现有链式前向星的做法,只要修改一下链表,而不用复制。但是前者复制反而会过,后者只是修改链表却超时…分析原因可能是链式前向星要初始化太多东西,多组输入就容易超时。
   为此,可以采用 l i s t list list 来记录, l i s t list list 有一个 s p l i c e splice splice 方法,可以完成两个链表的合并,这种方式比链式前向星写的手动链表要快。
   

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<double, double> P;
const int maxn = 8e5 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-11;
const ll mod = 1e9 + 7;

list<int> G[maxn];
int fa[maxn];

int Find(int x) { return fa[x] == x? x : fa[x] = Find(fa[x]); }

int main()
{
    int t, n, m, q, x;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d %d", &n, &m);
        for(int i = 0; i < n; i++)
        {
            fa[i] = i;               //初始化并查集和链表
            G[i].clear();
        }

        for(int i = 0; i < m; i++)
        {
            int x, y;
            scanf("%d %d", &x, &y);
            G[x].push_back(y);  G[y].push_back(x);
        }

        scanf("%d", &q);
        while(q--)
        {
            scanf("%d", &x);
            if(fa[x] != x)  continue;             //若是该组已经没有点
            int len = G[x].size(), y;
            for(int i = 0; i < len; i++)
            {
                y = G[x].front();  G[x].pop_front();
                y = Find(y);             //查找与这个组相邻的点
                if(y == x) continue;         //若是同属于一个组
                fa[y] = x;                         
                G[x].splice(G[x].end(), G[y]);           //修改链表
            }
        }

        for(int i = 0; i < n - 1; i++)
            printf("%d ", Find(i));
        printf("%d\n", Find(n - 1));
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值