码迷,mamicode.com
首页 > 编程语言 > 详细

AtCoder 4351 Median of Medians(二分+树状数组)

时间:2018-11-06 20:56:53      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:树状数组   inline   ==   i++   res   median   print   else   lse   

题意:给你列数,有一个中位数的定义,然后求出每一个区间的中位数,然后打印这些中位数的中位数

思路:没见过,真的学不来,看了聚聚们的博客以后,才学会。我们直接二分答案,我们有了答案以后,小于等于的mid的标记为1,其他的为-1,这样从一定程度上反应了区间大于和小于中位数的个数,对这个数组求前缀和,这样的话,我们变成了这样一个问题,我们如果找到一个正序数的一对数,这样这个区间的中位数就大于mid,这样的话,我们一直二分,会收敛到最后的中位数,因为二分是只需要判断能不能可行,不需要考虑答案是几,附一篇聚聚的博客(传送门

(chaoxi)代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
inline LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch>9||ch<0){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}

const int maxn=1e5+10;
int a[maxn];
int n;
int c[maxn*15];
int pre[maxn*15];
int lowbit(int x)
{
    return x&-x;
}
void add(int x)
{
    for(int i=x;i<=2*maxn;i+=lowbit(i))c[i]++;
}
LL query(int x)
{
    LL res=0;
    for(int i=x;i>0;i-=lowbit(i))res+=c[i];
    return res;
}

bool check(int x)
{
    memset(c,0,sizeof(c));
    pre[0]=0;
    for(int i=1;i<=n;i++)pre[i]=pre[i-1]+(a[i]>=x?1:-1);
    LL res=0;
    for(int i=0;i<=n;i++){
        res+=query(pre[i]+maxn);
        add(pre[i]+maxn);
    }
    return res>=1LL*n*(n+1)/4;
}

int main()
{
    n=read();
    int L=0,R=0,ans=0;
    for(int i=1;i<=n;i++){
        a[i]=read();
        R=max(R,a[i]);
    }
    while(L<=R){
        int mid=(L+R)>>1;
        if(check(mid)){
            L=mid+1;ans=mid;
        }
        else{
            R=mid-1;
        }
    }
    printf("%d\n",ans);
    return 0;
}

 

AtCoder 4351 Median of Medians(二分+树状数组)

标签:树状数组   inline   ==   i++   res   median   print   else   lse   

原文地址:https://www.cnblogs.com/lalalatianlalu/p/9917795.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!