ACM学习历程—51NOD 1685 第K大区间2(二分 && 树状数组 && 中位数)

http://www.51nod.com/contest/problem.html#!problemId=1685

这是这次BSG白山极客挑战赛的E题。

这题可以二分答案t。

关键在于,对于一个t,如何判断它是否能成为第k大。

将序列中大于t的置为1,小于t的置为-1,等于t的置为0。那么区间中位数大于t的和就大于0,小于t的就小于0。于是就是判断区间和大于0的个数是否小于等于k。

维护前缀和sum(i),然后统计之前sum(j)小于sum(i)的有多少个,就是以i为右值的区间和大于0的个数。于是就可以用树状数组维护了。

由于是奇数长度区间,所以树状数组需要维护奇偶长度的前缀和个数。需要特判sum(i) > 0的情况。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <string>
#define LL long long

using namespace std;

//线段树
//区间每点增值,求区间和
const int maxN = 100010;

LL d[2][maxN*2];

int lowbit(int x)
{
    return x&(-x);
}

void add(int t, int id,int pls)
{
    while(id <= maxN<<1)//id最大是maxN
    {
        d[t][id] += pls;
        id += lowbit(id);
    }
}

LL sum(int t, int to)
{
    LL s = 0;
    while(to > 0)
    {
        s = s + d[t][to];
        to -= lowbit(to);
    }
    return s;
}

LL query(int t, int from, int to)
{
    return sum(t, to) - sum(t, from-1);
}

int n, a[maxN], b[maxN];
LL k;

LL judge(int t)
{
    for (int i = 0; i < n; ++i)
    {
        if (a[i] > t) b[i] = 1;
        else if (a[i] == t) b[i] = 0;
        else b[i] = -1;
    }
    memset(d, 0, sizeof(d));
    int sum = 0;
    LL ans = 0;
    for (int i = 0; i < n; ++i)
    {
        sum += b[i];
        ans += query(!(i%2), 100005-n, 100005+sum-1);
        if (i%2 == 0 && sum > 0) ans++;
        add(i%2, 100005+sum, 1);
    }
    return ans;
}

void work()
{
    int lt, rt, mid;
    lt = rt = a[0];
    for (int i = 1; i < n; ++i)
    {
        lt = min(lt, a[i]);
        rt = max(rt, a[i]);
    }
    while ((LL)lt+1 < rt)
    {
        mid = ((LL)lt+rt)>>1;
        if (judge(mid) > k-1) lt = mid;
        else rt = mid;
    }
    if (judge(lt) <= k-1) printf("%d\n", lt);
    else printf("%d\n", rt);
}

int main()
{
    //freopen("test.in", "r", stdin);
    while (scanf("%d", &n) != EOF)
    {
        cin >> k;
        for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
        work();
    }
    return 0;
}

时间: 2024-08-08 08:05:39

ACM学习历程—51NOD 1685 第K大区间2(二分 && 树状数组 && 中位数)的相关文章

【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改

题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. 输入 第一行N,M接下来M行,每行形如1 a b c或2 a b c 输出 输出每个询问的结果 样例输入 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 样例输出 1 2 1 题解 整体二分+树状数组区间修改 当年naive的树套树题解 前两天由于要

51 NOD 1685 第K大区间2 二分+BIT

题目描述: 定义一个长度为奇数的区间的值为其所包含的的元素的中位数. 现给出n个数,求将所有长度为奇数的区间的值排序后,第K大的值为多少. 样例解释: [l,r]表示区间的值 [1]:3 [2]:1 [3]:2 [4]:4 [1,3]:2 [2,4]:2 第三大是2 输入: 第一行两个数n和k(1<=n<=100000,k<=奇数区间的数量) 第二行n个数,0<=每个数<2^31 输出: 一个数表示答案. 题解: 二分答案t,统计中位数大于等于t的区间有多少个. 设a[i]为

51nod 1686 第k大区间

1686 第K大区间 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 定义一个区间的值为其众数出现的次数.现给出n个数,求将所有区间的值排序后,第K大的值为多少. 众数(统计学/数学名词)_百度百科 Input 第一行两个数n和k(1<=n<=100000,k<=n*(n-1)/2) 第二行n个数,0<=每个数<2^31 Output 一个数表示答案. Input示例 4 2 1 2 3 2 Output示例 2 /* 51nod 1686

【51nod】 第K大区间2(二分+树状数组)

[51nod] 第K大区间2(二分+树状数组) 第K大区间2 ﹡    LH (命题人) 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 160 定义一个长度为奇数的区间的值为其所包含的的元素的中位数.中位数_百度百科 现给出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&l

【BZOJ3110】【整体二分+树状数组区间修改/线段树】K大数查询

Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M 接下来M行,每行形如1 a b c或2 a b c Output 输出每个询问的结果 Sample Input 2 5 1 1 2 1 1 1 2 2 2 1 1 2 2 1 1 1 2 1 2 3 Sample Output 1 2 1 HINT

【POJ2104】【整体二分+树状数组】区间第k大

Description You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array

【题解】51nod 1686第K大区间

成功的秘诀,在于克服自己看题解的冲动……[笑哭].自己A掉这题还是灰常开心的~ 以及爱死 two - pointer ! two - pointer 大法是真的好哇……这个题目有上一题的经验:求第\(K\) 大 --> 二分第 \(K\) 大的值 --> 检验当前二分的值排名是第几.而这样之所以可以解决问题在于:直接求第 \(K\) 并不好求,而检验一个值的排名却相对容易.所以我们现在的问题就转化为了如何计算出区间的值 \(>= mid\) 的区间的个数? 做题之前先找规律 &

51nod 平均数(二分+树状数组)

题目链接: 平均数 基准时间限制:4 秒 空间限制:131072 KB 分值: 80 LYK有一个长度为n的序列a. 他最近在研究平均数. 他甚至想知道所有区间的平均数,但是区间数目实在太多了. 为了方便起见,你只要告诉他所有区间(n*(n+1)/2个区间)中第k大的平均数就行了. Input 第一行两个数n,k(1<=n<=100000,1<=k<=n*(n+1)/2). 接下来一行n个数表示LYK的区间(1<=ai<=100000). Output 一行表示第k大的

ACM学习历程—51NOD 1412 AVL树的种类(递推)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1770 这是这次BSG白山极客挑战赛的B题.设p(i, j)表示节点个数为i,高度为j的AVL树的个数. 那么,对于1 <= k <= i-1 p[i][j] += p[k][j-1]*p[i-1-k][j-1]%MOD; p[i][j] += p[k][j-2]*p[i-1-k][j-1]%MOD; p[i][j] += p[k][j-1]*p[i-1-k][j-2]