H - Almost Union-Find
//带删除操作的并查集 //题意:给你一个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; }