题意:
有N只猫,开始每只猫都是一个小组,下面要执行M个操作。
操作0 i j 是把i猫和j猫所属的小组合并。
操作1 k 是问你当前第k大的小组大小是多少. 且k<=当前的最大组数.
题解:
Treap实现名词树+并查集,并查集根节点root:pa[root] = -规模。
/** treap求第k大 */ #include<cstdlib> #include<cstring> #include<cstdio> using namespace std; const int maxn = 2e5+999; int n,m,cnt; int pa[maxn]; /**并查集*/ struct node { node* ch[2]; int r,v,s; node(int v):v(v) { r = rand(); s = 1; ch[0] = ch[1] = NULL; } void maintain() { s = 1; if(ch[0])s+=ch[0]->s; if(ch[1])s+=ch[1]->s; } int cmp(int x) { if(x==v)return -1; return x<v?0:1; } }*root; void Rotate(node* &o,int d) { node *k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o; o->maintain(); k->maintain(); o=k; } void Insert(node* &o,int v) { if(o==NULL)o = new node(v); else { int d = v<o->v? 0:1; Insert(o->ch[d],v); if(o->ch[d]->r > o->r) Rotate(o,d^1); } o->maintain(); } void Remove(node* &o,int v) { int d = o->cmp(v); if(d == -1) { if(o->ch[0] && o->ch[1]) { int d2 = o->ch[0]->r < o->ch[1]->r? 0 : 1; Rotate(o,d2); Remove(o->ch[d2],v); } else { node* u = o; if(!o->ch[0])o=o->ch[1]; else o = o->ch[0]; delete u; } } else Remove(o->ch[d],v); if(o) o->maintain(); } int kth(node *o,int k)///第k大 { int s = (o->ch[1]==NULL)?0:o->ch[1]->s; if(k==s+1)return o->v; else if(k<=s)return kth(o->ch[1],k); else return kth(o->ch[0],k-s-1); } ///并查集部分 int findset(int x) { return pa[x]<0? x : pa[x] = findset(pa[x]); } void unionset(int x,int y) { int rx = findset(x); int ry = findset(y); if(rx != ry) { if(pa[rx]!=-1){Remove(root,-pa[rx]);cnt--;}/**根节点的pa放集合内元素数量的相反数*/ if(pa[ry]!=-1)Remove(root,-pa[ry]),cnt--; Insert(root,-pa[rx]-pa[ry]); cnt++; pa[ry] += pa[rx]; pa[rx] = ry; } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { root = NULL; cnt = 0; memset(pa,-1,sizeof pa); while(m--) { int op,i,j,k; scanf("%d",&op); if(op==0) { scanf("%d%d",&i,&j); unionset(i,j); } else { scanf("%d",&k); if(k>cnt)printf("1\n"); else printf("%d\n",kth(root,k)); } } } return 0; }