2020 牛客多校4 G(並查集)
阿新 • • 發佈:2020-07-19
題意:就是將一個集合所有與其直接相連的集合合併,被合併的集合消失。比如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; }