D - Median of Medians (atcoder.jp)
中位数和平均数都有01串的性质,所以我们可以先二分答案mid,找到有哪些数大于等于mid设为1,哪些数小于mid设为-1,然后找哪些区间有至少n/2个正数即转变成了和大于等于0的区间有多少个,那么自然想到要用前缀和处理一下,这样可以o1内查询一段区间的和。然后就转变成了一个经典的二位偏序的题目——即x<y且sum[x]<=sum[y]的区间有多少个,即可利用树状数组或者归并排序的做法解决。
#include<bits/stdc++.h>
#define PII pair<int,int>
#define PLL pair<long long,long long>
#define fi first
#define se second
#define endl '\n'
#define bug printf("bug\n");
using namespace std;
const int N=2e5+10;
const int INF=0x3f3f3f3f;
const long long LNF=0x3f3f3f3f3f3f3f3f;
const long long mod=1e9+7;
long long n;
long long s[N],st[N],sum[N];
long long res=0,num=0;
void mergesort(long long l,long long r){
if(l==r) return ;
long long mid=(l+r)>>1;
mergesort(l,mid); mergesort(mid+1,r);
long long v1=l,v2=mid+1,cnt=l;
while(v1<=mid&&v2<=r){
if(sum[v1]<sum[v2]) st[cnt++]=sum[v1++];
else res=res+(v1-l),st[cnt++]=sum[v2++];
}
while(v1<=mid) st[cnt++]=sum[v1++];
while(v2<=r) res=res+(v1-l),st[cnt++]=sum[v2++];
for(long long i=l;i<=r;i++) sum[i]=st[i];
}
bool check(int mid){
res=0;
for(int i=1;i<=n;i++){
if(s[i]<=mid) sum[i]=1;
else sum[i]=-1;
}
for(int i=1;i<=n;i++) sum[i]=sum[i-1]+sum[i];
//for(int i=1;i<=n;i++) printf("%d ",sum[i]); puts("");
mergesort(0,n);
//printf("%d %d\n",mid,res);
return res>=num/2+1;
}
void solve(){
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld",&s[i]);
long long l=INF,r=0;
for(long long i=1;i<=n;i++){
l=min(l,s[i]); r=max(r,s[i]);
}
num=(n+1)*n/2;
//printf("%lld\n",num);
//printf("%d %d\n",l,r);
while(l<r){
long long mid=(l+r)>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
printf("%lld\n",l);
}
int main(){
int t=1;
//scanf("%d",&t);
while(t--){
solve();
}
return 0 - 0;
}