题目链接:POJ 2985 The k-th Largest Group
并查集 + 树状数组。
主要考察点是用树状数组求第k小的数。其中用到了二分法。
#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;
const int MAX_N = 200000 + 100;
int n,m;
int num[MAX_N],p[MAX_N],a[MAX_N];
int lowbit(int i)
{
return i & (-i);
}
void add(int i,int val)
{
while(i <= n)
{
num[i] += val;
i += lowbit(i);
}
}
int sum(int i)
{
int ans = 0;
while(i > 0)
{
ans += num[i];
i -= lowbit(i);
}
return ans;
}
int find(int x)
{
return p[x] == x ? x : p[x] = find(p[x]);
}
int main()
{
while(scanf("%d %d",&n,&m) != EOF)
{
memset(num,0,sizeof(num));
for(int i = 1;i <= n;i++)
a[i] = 1;
for(int i = 1;i <= n;i++)
p[i] = i;
int cnt = n;
add(1,n);
int temp;
int _a,_b;
for(int i = 0;i < m;i++)
{
scanf("%d",&temp);
if(temp == 1)
{
scanf("%d",&_a);
_a= cnt - _a + 1;//转换为找第k小的数
int l = 1;
int r = n;
while(l <= r)
{
int mid = (l + r) >> 1;
if(sum(mid) >= _a)
r = mid - 1;
else
l = mid + 1;
}
printf("%d\n",l);
}
else
{
scanf("%d %d",&_a,&_b);
_a = find(_a);
_b = find(_b);
if(_a == _b)
continue;
p[_b] = _a;
add(a[_a],-1);
add(a[_b],-1);
add(a[_a] = a[_a] + a[_b],1);
cnt--;
}
}
}
return 0;
}