方法一
树状数组 + 二分
优点:实现简单,原理简单
缺点:只能对整体查询,不能查询区间第k大,而且要求数字不能太大
复杂度:查询一次
l
o
g
2
(
n
)
log^2(n)
log2(n)
原理:树状数组中T[i]存储大小为
i
−
l
o
w
b
i
t
(
i
)
到
i
i-lowbit(i) 到 i
i−lowbit(i)到i的数出现的次数, 查询时二分这个数即可,判断当前数是否为第k大数(直接用当前总数 - 查询得到的比i小的数)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define lowbit(x) x & (-x)
const int N = 2e5 + 10;
int t[N], n, m;
void add(int x, int k)
{
for(int i = x; i <= n; i += lowbit(i))
{
t[i] += k;
}
}
int fa[N];
int num[N];
int sum;
int find_(int x)
{
return fa[x] == x ? x : fa[x] = find_(fa[x]);
}
int query(int x)
{
int all = 0;
for(int i = x; i; i -= lowbit(i)) all += t[i];
return all;
}
int check(int x)
{
return sum - query(x - 1);
}
int main()
{
scanf("%d%d", &n, &m);
add(1, n);
sum = n;
for(int i = 1; i <= n; i ++) fa[i] = i, num[i] = 1;
for(int i = 1; i <= m; i ++)
{
int op;
scanf("%d", &op);
if(op == 0)
{
int x, y;
scanf("%d%d",&x, &y);
int x1 = find_(x), y1 = find_(y);
if(x1 == y1) continue;
add(num[x1], -1), add(num[y1], -1);
sum --;
fa[x1] = y1;
num[y1] += num[x1];
add(num[y1], 1);
}
else
{
int x;
scanf("%d", &x);
int l = 1, r = n;
while(l < r)
{
int mid = l + r >> 1;
int tmp = query(n) - query(mid);
//cout << tmp << endl;
if(tmp < x)
{
r = mid;
}
else
{
l = mid + 1;
}
}
printf("%d\n", l);
}
}
}