[二分+樹狀數組]51 Nod 1685——第K大區間2
題目描述
定義一個長度爲奇數的區間的值爲其所包含的的元素的中位數。
現給出n個數,求將所有長度爲奇數的區間的值排序後,第K大的值爲多少。
解題思路
二分枚舉答案x。
考慮如何驗證中位數>=x的區間總數是否>=K。
構造
如果一個區間的中位數
轉移之後得到
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=100005;
int a[maxn*2][2],s[maxn],w[maxn],L,R,mid,n;
LL K;
int lowbit(int x){return x&(-x);}
void add(int x,int id){for (;x<=2*n+2;x+=lowbit(x)) a[x][id]++;}
int ask(int x,int id){int num=0;for (;x>0;x-=lowbit(x)) num+=a[x][id];return num;}
bool check(int x){
memset(a,0,sizeof(a));
for (int i=1;i<=n;i++) s[i]=s[i-1]+(w[i]>=x);
LL sum=0;add(n+2,0);
for (int i=1;i<=n;i++) sum+=ask(s[i]*2-i+n-1+2,1-(i%2)),add(s[i]*2-i+n+2,i%2);
return sum>=K;
}
int main(){
freopen("exam.in","r",stdin);
freopen("exam.out","w",stdout);
scanf("%d%lld",&n,&K);
for (int i=1;i<=n;i++) scanf("%d",&w[i]),R=max(w[i],R);
while(L<=R){
mid=L+(R-L>>1);
if (check(mid)) L=mid+1;else R=mid-1;
}
printf("%d\n",R);
return 0;
}