[二分+樹狀數組]51 Nod 1685——第K大區間2

[二分+樹狀數組]51 Nod 1685——第K大區間2

題目描述

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

解題思路

二分枚舉答案x。

考慮如何驗證中位數>=x的區間總數是否>=K。

構造s[i] 表示前i個數有多少個數>=x

如果一個區間的中位數>=x 肯定有(s[R]s[L1])2>RL+1

轉移之後得到s[R]2R>s[L1]2(L1) ,這個東西用樹狀數組維護就可以了。

#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;
}
發佈了157 篇原創文章 · 獲贊 61 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章