UVA11987Almost Union-Find(并查集删除节点)

时间:2022-01-26 19:45:53

题目链接

题意:n个数(即1-n)和m个操作:

1表示把x和y合并,2表示把x移到y集合里面,3表示统计x集合的元素个数

1,3好说,关键是2操作,可以先把2删除掉,删除的操作可以找一个其他的数字来取代x,这样就有新生出来一个集合,移到y集合就合并

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100000;
typedef long long LL;
int father[N + N + 10];
int sum[N + N + 10],cnt[N + N + 10]; // sum求集合里面所有元素和,cnt表示个数
int value[N + N + 10]; //表示第i个数值
int n,m,k;
void init()
{
k = n + 1;
for(int i = 0; i <= n; i++)
{
father[i] = i;
sum[i] = i;
cnt[i] = 1;
value[i] = i;
}
}
int Find(int x)
{
if(x == father[x])
return x;
return father[x] = Find(father[x]);
}
void Union(int x, int y)
{
int fx = Find(x);
int fy = Find(y);
if(fx != fy)
{
father[fx] = fy;
sum[fy] += sum[fx];
cnt[fy] += cnt[fx];
}
}
void Remove(int x)
{
/*
int fx = Find(value[x]);
cnt[fx]--;
sum[fx] -= x;
value[x] = k;
int fy = Find(value[y]);
father[k] = fy;
cnt[fy]++;
sum[fy] += x;
k++;
*/
int fx = Find(value[x]);
cnt[fx]--; // 删除x时从父节点集合中减一
sum[fx] -= x; // sum中减去x
value[x] = k; // 用 k 来代替 x ,生成了一个单独的集合,父节点是k
cnt[k] = 1;
sum[k] = x;
father[k] = k;
k++;
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF)
{
k = n + 1;
for(int i = 0; i <= n; i++)
{
father[i] = i;
sum[i] = i;
cnt[i] = 1;
value[i] = i;
}
int order,p,q;
while(m--)
{
scanf("%d", &order);
if(order == 1)
{
scanf("%d%d", &p, &q);
Union(value[p], value[q]);
}
else if(order == 2)
{
scanf("%d%d", &p, &q);
int fx = Find(value[p]);
int fy = Find(value[q]);
if(fx != fy) // 如果p和q本来就在一个集合,就不用操作了。但是少了这个就wa了,不明白为什么操作不行
{
Remove(p);
Union(value[p], value[q]);
}
}
else if(order == 3)
{
scanf("%d", &p);
int fx = Find(value[p]);
printf("%d %d\n", cnt[fx], sum[fx]);
}
}
}
return 0;
}