ARC 101D 二分答案 树状数组 转化

题目链接

这个题鸽的有点久了… 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值