【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);
}