1. 程式人生 > >【51Nod1685】第K大區間2

【51Nod1685】第K大區間2

定義一個長度為奇數的區間的值為其所包含的的元素的中位數。中位數_百度百科
現給出n個數,求將所有長度為奇數的區間的值排序後,第K大的值為多少。

樣例解釋:

[l,r]表示區間的值
[1]:3
[2]:1
[3]:2
[4]:4
[1,3]:2
[2,4]:2

第三大是2
Input
第一行兩個數n和k(1<=n<=100000,k<=奇數區間的數量)
第二行n個數,0<=每個數<2^31
Output
一個數表示答案。
Input示例
4 3
3 1 2 4
Output示例
2

題解
這類區間第k大基本二分答案。
記sum[i]表示1-i裡大於mid的數的個數
區間符合條件滿足2*(sum[R]-sum[L-1])>R-(L-1)
即2*sum[R]-R>sum[L-1]-(L-1) 且為奇區間

程式碼

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,a[100005],ls[100005
],t[2][300005],sum[100005]; ll k; int lowbit(int x){return x&-x;} inline void update(int p,int x) { for (;x<=3*n;x+=lowbit(x))t[p][x]++; } int query(int p,int x) { int ans=0; for (;x;x-=lowbit(x))ans+=t[p][x]; return ans; } bool judge(int mid) { for (int i=1;i<=n;i++) sum[i]=sum[i-1
]+(a[i]>=mid); for (int i=1;i<=n;i++) sum[i]=2*sum[i]-i+n; memset(t,0,sizeof(t));update(0,n); ll ans=0; for (int i=1;i<=n;i++) { ans+=query(!(i&1),sum[i]-1); update(i&1,sum[i]); } return ans>=k; } int main() { n=read();scanf("%lld",&k); for (int i=1;i<=n;i++) a[i]=read(),ls[i]=a[i]; sort(ls+1,ls+n+1); int l=1,r=n; while (l!=r) { int mid=(l+r+1)>>1; if (judge(ls[mid])) l=mid;else r=mid-1; } printf("%d",ls[l]); return 0; }