![]()
![]()
//带删除操作的并查集
//题意:给你一个1~n的集合,有三种操作
// 1: 把p和q所在的集合合并
//2:把p移到q所在的集合中
//3:返回p所在集合中的元素个数和元素的和
//第二种操作不能直接把p的father改成q的father,因为这样p的子树也都换了爸爸
//对于每个元素,我们可以记录它所在的位置pos,合并的时候新申请一个pos,然后让这个元素的位置指向pos,再把pos和q合并
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=2e5+5;
int n,m;
int opt,p,q;
struct Node
{
Node *fa,*pos;
int key;
int cnt,sum;
}node[N];
typedef Node* Tree;
Tree now_node;
int read()
{
char c=getchar();int num=0,f=1;
for(;!isdigit(c);c=getchar())
f=c=='-'?-1:f;
for(;isdigit(c);c=getchar())
return num*10+c-'0';
return num;
}
void init()
{
now_node=node;
for(int i=0;i<=n;++i,++now_node)
{
now_node->key=i;
now_node->cnt=1;
now_node->sum=i;
now_node->fa=now_node;
now_node->pos=now_node;
// (node+i)->cnt=(node+i)->sum=0;
// (node+i)->fa=(node+i);
// (node+i)->pos=(node+i);
}
//now_node=(node+n);
}
Tree find(Tree x)
{
return x->fa==x?x:x->fa=find(x->fa);
}
void unionn(Tree a,Tree b)
{
Tree fa=find(a),fb=find(b);
if(fa==fb)
return;
fa->fa=fb;
fb->cnt+=fa->cnt;
fb->sum+=fa->sum;
}
void move(Tree a)
{
Tree fa=find(a->pos);
--fa->cnt;
fa->sum-=a->key;
++now_node;
now_node->key=a->key;
now_node->cnt=1;
now_node->sum=a->key;
now_node->fa=now_node;
a->pos=now_node;
}
int main()
{
while(scanf("%d%d",&n,&m)==2)
{
init();
while(--m)
{
opt=read();
if(opt==1)
{
p=read(),q=read();
unionn((node+p)->pos,(node+q)->pos);
}
else if(opt==2)
{
p=read(),q=read();
Tree fa=find((node+p)->pos);
Tree fb=find((node+q)->pos);
if(fa!=fb)
{
move(node+p);
unionn((node+p)->pos,(node+1)->pos);
}
}
else
{
p=read();
Tree fa=find((node+p)->pos);
printf("%d %d\n",fa->cnt,fa->sum);
}
}
}
return 0;
}