【GDOI2006】The Kth Element

\(Solution\)

先二分答案,考虑去求\(ans\)的排名,那么相当于去求有多少和是小于\(ans\),对原序列做前缀和,问题转化成了求所有的\(S_r - S_l < ans \implies S_l > Sr - ans\)枚举一个\(S_r\)\(S_l\)加入线段树中即可。

\(Code\)

#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int N = 2e4 + 5;
int n,K,f[N << 2],len;
LL a[N],b[N],c[N];

void update(int l,int r,int k,int u,int v)
{
	if (l == r) return f[k] += v,void();
	int mid = l + r >> 1;
	if (u <= mid) update(l,mid,k << 1,u,v);
	else update(mid + 1,r,k << 1 | 1,u,v);
	f[k] = f[k << 1] + f[k << 1 | 1]; 
}
int query(int l,int r,int k,LL v)
{
	if (l == r) return b[l - 1] > v ? f[k] : 0;
	int mid = l + r >> 1;
	if (b[mid - 1] < v) return query(mid + 1,r,k << 1 | 1,v);
	return f[k << 1 | 1] + query(l,mid,k << 1,v);
}
int check(LL x)
{
	for (int i = 0; i <= n; i++) update(1,len + 1,1,c[i],1);
	LL res = 0;
	for (int i = n; i >= 0; i--)
		update(1,len + 1,1,c[i],-1),res += (LL)query(1,len + 1,1,a[i] - x);
	return res < K;
}
int main()
{
	scanf("%d%d",&n,&K);
	for (int i = 1,q; i <= n; i++) 
		scanf("%d",&q),a[i] = a[i - 1] + (LL)q,b[i] = c[i] = a[i];
	sort(b,b + 1 + n),len = unique(b,b + 1 + n) - b - 1;
	for (int i = 0; i <= n; i++) c[i] = lower_bound(b,b + 1 + len,c[i]) - b + 1;
	LL l = -1e16,r = 1e16,ans = -1;
	while (l <= r)
	{
		LL mid = l + r >> 1;
		if (check(mid)) ans = mid,l = mid + 1;
		else r = mid - 1;
	}
	printf("%lld\n",ans);
}
posted @ 2022-01-23 14:45  RiverSheep  阅读(34)  评论(0编辑  收藏  举报