1. 程式人生 > 實用技巧 >2020 牛客多校4 G(並查集)

2020 牛客多校4 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;
}