2022.10.15 总结

C

中位数定义为第 \(\lfloor \dfrac{n}{2} \rfloor+1\) 个数。
现有一个数组 \(a\) , \(n\le10^5\).
对于 \(1\le l \le r \le n\),求区间 \([l,r]\) 的中位数,
把这些中位数构成一个大小为 \(\dfrac{1}{2}n(n+1)\)\(b\) 数组,求 \(b\) 数组的中位数。

Hint 1: 二分一个数 \(mid\),若小于 \(mid\) 的个数小于等于 \(\lfloor \dfrac{\frac{1}{2}n(n+1)}{2} \rfloor\),则中位数大于等于 \(mid\).
Hint 2: 在数组 \(a\) 内,把 \(\ge mid\) 的标记为 \(1\), \(< mid\) 的标记为 \(-1\),若子串和为非负数,则其中位数大于等于 \(mid\).

code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,a[N],b[N],rk[N],q[N],c[2*N],m;
void modify(int x,int v) {
	x+=N;
	for(; x<2*N; x+=x&-x) c[x]+=v;
}
int query(int x) {
	x+=N; int res=0;
	for(; x; x-=x&-x) res+=c[x];
	return res;
}
bool check(int p) {
	int sum=0;
	memset(c,0,sizeof(c));
	for(int i=1; i<=n; i++) {
		if(a[i]>=p) q[i]=1;
		else q[i]=-1;
	}
	for(int i=1; i<=n; i++) q[i]+=q[i-1];
	modify(0,1);
	for(int i=1; i<=n; i++) {
		sum+=query(q[i]);
		modify(q[i],1);
	}
	return (sum>=n*(n+1)/2/2);
}
signed main() {
	freopen("middle.in","r",stdin);
	freopen("middle.out","w",stdout);
	scanf("%lld",&n);
	for(int i=1; i<=n; i++) {scanf("%lld",&a[i]); b[i]=a[i];}
	sort(b+1,b+1+n); m=unique(b+1,b+1+n)-b-1;
	for(int i=1; i<=n; i++) {
		int x=lower_bound(b+1,b+1+m,a[i])-b;
		rk[x]=a[i]; a[i]=x;
	}
	int l=0,r=m+1;
	for(; l+1<r; ) {
		int mid=(l+r)/2;
		if(check(mid)) l=mid;
		else r=mid;
	}
	printf("%lld\n",rk[l]);
	return 0;
} 
posted @ 2022-10-17 12:56  s1monG  阅读(25)  评论(0编辑  收藏  举报