描述
题解
二分 + 树状数组。
二分枚举答案,判断中位数大于等于当前答案的个数是否足够 k 个,至于怎么判断,我们需要借助树状数组。首先我们可以通过前缀的方法获取前
十分有趣的一个题,注意奇偶性的问题,这也是为什么要使用两棵树状数组的原因,这样就能保证每次查找的区间都是奇数个,就这样,没什么了。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 10;
int n;
ll k;
int a[MAXN];
int b[MAXN];
int c[MAXN];
int sum[MAXN];
int tree[2][MAXN * 3];
void add(int rt, int x, int y = 1)
{
if (x <= 0)
{
return ;
}
int tmp = 3 * n;
for (; x <= tmp; x += x & -x)
{
tree[rt][x] += y;
}
}
int get_sum(int rt, int x)
{
if (x <= 0)
{
return 0;
}
int ret = 0;
for (; x; x -= x & -x)
{
ret += tree[rt][x];
}
return ret;
}
ll check(int x)
{
ll ret = 0;
memset(tree, 0, sizeof(tree));
for (int i = 1; i <= n; i++)
{
sum[i] = sum[i - 1] + (a[i] >= x);
c[i] = 2 * sum[i] - i + n; // +n 是偏移一下,以防负数
}
add(0, n);
for (int i = 1; i <= n; i++)
{
add(i & 1, c[i]);
ret += get_sum((i + 1) & 1, c[i] - 1);
}
return ret;
}
template <class T>
inline void scan_d(T &ret)
{
char c;
ret = 0;
while ((c = getchar()) < '0' || c > '9');
while (c >= '0' && c <= '9')
{
ret = ret * 10 + (c - '0'), c = getchar();
}
}
int main()
{
scan_d(n), scan_d(k);
for (int i = 1; i <= n; i++)
{
scan_d(a[i]);
b[i] = a[i];
}
sort(b + 1, b + n + 1);
int l = 1, r = n + 1, m;
while (l + 1 < r)
{
m = (l + r) >> 1;
if (check(b[m]) >= k)
{
l = m;
}
else
{
r = m;
}
}
printf("%d\n", b[l]);
return 0;
}