2020 牛客多校3 G(并查集)

题意

就是将一个集合所有与其直接相连的集合合并,被合并的集合消失。比如1并到0中,那么0,1所属的集合都为0。

解法

题目中直接开队列开不下,改成vector合并集合会T,看大佬的代码,发现用链式前向星做边,再加个tail数组用来O(1)合并就行(也可以用list的splice()合并,都是O(1)的),向当于将另一集合中的所有边并到这一集合中。
另外得跳过已经被其他集合合并过的点,并且在合并过程中得预先存下tail,因为合并的时候会更新tail

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 8e5 + 7;

int t;
int n, m;
int head[N], tail[N];
struct edge{
    int to, nxt;
} e[N << 1];
int u, v, cnt = 0;
int f[N];
int q;

inline int read_int()
{
    char c;
    int ret = 0, sgn = 1;
    do
    {
        c = getchar();
    } while ((c < '0' || c > '9') && c != '-');
    if (c == '-') sgn = -1;
    else ret = c - '0';
    while ((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    return sgn * ret;
}
inline ll read_ll()
{
    char c;
    ll ret = 0, sgn = 1;
    do
    {
        c = getchar();
    } while ((c < '0' || c > '9') && c != '-');
    if (c == '-') sgn = -1;
    else ret = c - '0';
    while ((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    return sgn * ret;
}

void addedge(int u, int v)
{
    e[++cnt].nxt = head[u];
    e[cnt].to = v;
    if(e[cnt].nxt == 0)
    {
        tail[u] = cnt;
    }
    head[u] = cnt;
}

int find(int x)
{
    if(x != f[x]) return f[x] = find(f[x]);
    return x;
}


void merge(int u, int v)
{
    e[tail[u]].nxt = head[v];
    tail[u] = tail[v];
}
void unio(int x, int y)
{
    int fx = find(x);
    int fy = find(y);
    
    if(fx != fy)
    {
        f[fy] = fx;
        merge(fx, fy);
    }
}


int main()
{
    scanf("%d",&t);
    while (t--)
    {
        n = read_int(), m = read_int();
        for (int i = 0; i < n;i++)
        {
            f[i] = i;
            head[i] = tail[i] = 0;
        }
        for (int i = 0; i < m; i++)
        {
            u = read_int(), v = read_int();
            addedge(u, v);
            addedge(v, u);
        }
        q = read_int();
        while(q--)
        {
            u = read_int();
            if(find(u) != u) continue;
            for (int i = head[u], t = tail[u]; i;i = e[i].nxt)
            {
                unio(u, e[i].to);
                if(i == t) break;
            }
        }
        for (int i = 0; i < n;i++)
        {
            printf("%d%c", find(i), " \n"[i == n - 1]);
        }
    }
    return 0;
}
posted @ 2020-07-19 13:26  Cyan_Cloud  阅读(124)  评论(0编辑  收藏  举报