这个题鸽的有点久了… C h e c k m a t e Checkmate Checkmate过生日那天的题 看了网上的题解看懂的
首先区间数目太多了肯定是求不出来的 我们首先二分最后的答案 m i d mid mid
我们把大于等于这个 m i d mid mid的数设为 1 1 1,小于等于的设为 − 1 -1 −1
记录前缀和 每次加入一个数 我们查询在它之前前缀和小于等于它的个数
像树状数组求逆序对那样 那么就可以得到中位数大于当前二分的值的区间个数
然后就做完了 复杂度 O ( n l o g n l o g L ) O(nlognlogL) O(nlognlogL)
###注意下二分边界!!!
Codes
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int limit = 1e5 + 1;
int a[N], n;
long long res;
struct Fenwick_Tree {
int s[N];
void clear() {memset(s, 0, sizeof(s));}
void update(int x, int y) {for(; x <= n + limit; x += x & -x) s[x] += y;}
int query(int x) {int res = 0; for(; x; x -= x & -x) res += s[x]; return res;}
}T;
bool check(int x) {
int sum = limit; res = 0;
T.clear(); T.update(sum, 1);
for(int i = 1; i <= n; ++ i) {
sum += a[i] >= x ? 1 : -1;
res += T.query(sum);
T.update(sum, 1);
}
long long tot = 1ll * n * (n + 1) / 2;
return res > (tot - (tot / 2 + 1));
}
int main() {
int ans, l = 1, r = 1e9;
scanf("%d", &n);
for(int i = 1; i <= n; ++ i)
scanf("%d", &a[i]);
while(l <= r) {
int mid = (l + r) >> 1;
if(check(mid)) ans = mid, l = mid + 1;
else r = mid - 1;
}
printf("%d\n", ans);
return 0;
}