1.题目描述:点击打开链接
2.解题思路:本题利用并查集解决。唯一一个和普通的并查集不太一样的操作就是题目中的操作2,要求将p从它所在的集合中移出,移到q所在的集合。这就提示我们不要让数字本身作为该并查集的树根。因此,我们可以统一把树根都设置为i+n,这样,就可以保证每个数字不会成为并查集的树根了。那么对于操作2,先执行x=findset(p), y=findset(q)。只需要令pa[p]=y即可(因为可以保证此时pa[p]=x),其他操作和普通并查集操作完全一样。
3.代码:
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<complex>
#include<functional>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define rep(i,n) for(int i=0;i<(n);i++)
#define me(s) memset(s,0,sizeof(s))
#define pb push_back
#define lid (id<<1)
#define rid (id<<1|1)
typedef long long ll;
typedef pair<int,int> P;
const int N = 200000 + 10;
int pa[N];
int C[N];
int sum[N];
int n, m;
int findset(int x) { return pa[x] == x ? x : pa[x] = findset(pa[x]); }
int main()
{
while (~scanf("%d%d", &n, &m))
{
for (int i = 1; i <= n; i++)
pa[i] = i + n, sum[i + n] = i, C[i + n] = 1;
for (int i = 1; i <= n; i++)
pa[i + n] = i + n;
int type, p, q;
for (int i = 0; i<m; i++)
{
scanf("%d", &type);
if (type == 1)
{
scanf("%d%d", &p, &q);
int x = findset(p), y = findset(q);
if (pa[x] != y)
{
sum[y] += sum[x];
C[y] += C[x];
pa[x] = y;
}
}
else if (type == 2)
{
scanf("%d%d", &p, &q);
int x = findset(p), y = findset(q);
if (pa[x] != y)
{
pa[p] = y;
C[x]--, C[y]++;
sum[x] -= p, sum[y] += p;
}
}
else
{
scanf("%d", &p);
int x = findset(p);
printf("%d %d\n", C[x], sum[x]);
}
}
}
}