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;
}