题意大概是:两种操作,合并集合,求元素第k多的集合有多少个元素
集合的合并就用并查集,同时维护一个数组tol表示该集合中的元素个数
树状数组,存值为i的个数,sum(i)表示值小于等于i的个数
树状数组求第k大,用二分法即可
#include <cstdio>
#include <cstring>
const int MAX = 200010;
int b[MAX];
int a[MAX],tol[MAX];
int n,m;
int find(int x)
{
return x==a[x]?x:a[x] = find(a[x]);
}
int lowbit(int x)
{
return x&(-x);
}
void plus(int x,int c)
{
while(x<=n)
{
b[x]+=c;
x+=lowbit(x);
}
}
int sum(int x)
{
int ans = 0;
while(x)
{
ans+=b[x];
x-=lowbit(x);
}
return ans;
}
int query(int k)
{
int low = 1;
int high = n;
while(high>low)
{
int mid = low+high>>1;
if(sum(mid)>=k)
high = mid;
else low = mid+1;
}
return low;
}
int main()
{
int c,x,y;
while(scanf("%d%d",&n,&m)==2)
{
int g = n;
memset(b,0,sizeof(b));
for(int i=1; i<=n; i++)
{
a[i] = i;
tol[i] = 1;
}
plus(1,n);
while(m--)
{
scanf("%d",&c);
if(c)
{
scanf("%d",&x);
printf("%d\n",query(g-x+1));
}
else
{
scanf("%d%d",&x,&y);
int fx = find(x);
int fy = find(y);
if(fx!=fy)
{
if(tol[fx]==tol[fy])
plus(tol[fx],-2);
else
{
plus(tol[fx],-1);
plus(tol[fy],-1);
}
plus(tol[fx]+tol[fy],1);
tol[fy]+=tol[fx];
tol[fx] = 0;
a[fx] = fy;
g--;
}
}
}
}
return 0;
}