• HDU 2852 (树状数组+无序第K小)


    题目大意:操作①:往盒子里放一个数。操作②:从盒子里扔掉一个数。操作③:查询盒子里大于a的第K小数。

    解题思路

    由于模型是盒子,而不是序列,所以可以用树状数组的顺序维护+逆序数思想。

    放一个数

    Add(val,1)Add(val,1)

    类似维护逆序数的方法,对应位置上计数+1。

    注意Add的while范围要写成while(x<maxn)while(x<maxn)

    如果范围不是最大,那么会导致某些sum[x]不会被更新。

    删一个数

    判断:getSum(val)getSum(val1)=0getSum(val)−getSum(val−1)=0

    可以Hash处理,但是没有必要。如果没有val这个数,那么getSum(val)=getSum(val1)getSum(val)=getSum(val−1)是必然的。

    删除:Add(val,1)Add(val,−1)

    即加上-1,撤销之前的操作。

    查询

    查询比较麻烦。

    首先要判断getSum(maxn1)getSum(val)>=kgetSum(maxn−1)−getSum(val)>=k

    然后,将查询大于a的第K小数转化为大于1的第X+K小数。

    其中X=getSum(val)X=getSum(val)。然后,对区间[1,maxn][1,maxn]进行二分。

    二分处理手段比较特殊,主要是由于有重复的数,所以直接找出argminmidgetSum(mid)=X+Karg⁡minmidgetSum(mid)=X+K是不行的。

    getSum(mid)=X+KgetSum(mid)=X+K有时候并不能二分找到。

    解决方法是:

    R=mid(getSum(mid)<=X+K)

    L=mid(other)

    这样,如果没有二分到,会最近的最小R作为结果。

    ans=R

    AC代码:

    #include<stdio.h>
    #include<string.h>
    #define lowbit(i) (i&(-i))
    using namespace std;
    const int maxn = 1e5+1;
    int c[maxn];
    inline void add(int i, int val)
    {
        while(i<=100000){
            c[i] += val;
            i += lowbit(i);
        }
    }
    int sum(int i)
    {
        int ans = 0;
        while(i>0){
            ans += c[i];
            i -= lowbit(i);
        }
        return ans;
    }
    int vis[maxn];
    int Bin_search(int L, int R, int key, int index)
    {
        int mid;
        while(L < R){
            mid = L + ((R-L)>>1);
            if(sum(mid) - sum(index)  < key) L = mid + 1;
            else R = mid;
        }
        return R;
    }
    int main(void)
    {
        int n;
        while(~scanf("%d", &n) && n){
            memset(c, 0, sizeof(c));
            memset(vis, 0, sizeof(vis));
            int command;
            int tot = 0;
            int M = 0;
            for(int t=1; t<=n; t++){
                scanf("%d", &command);
                if(command==0){
                    int temp;
                    scanf("%d", &temp);
                    if(temp>M) M = temp;
                    vis[temp]++;
                    add(temp, 1);
                    tot++;
                }
                else if(command==1){
                    int temp;
                    scanf("%d", &temp);
                    if(vis[temp]){
                        tot--;
                        add(temp, -1);
                        vis[temp]--;
                    }else{
                        puts("No Elment!");
                    }
                }
                else{
                    int a, b;
                    int ans;
                    scanf("%d%d", &a, &b);
                    if(tot-sum(a) >= b){
                        int ans = Bin_search(a, M, b, a);
                        printf("%d
    ", ans);
                    }else{
                        puts("Not Find!");
                    }
                }
            }
        }
        return 0;
    }
    View Code

     前面思路还可以,但到后面的查询操作就不能很快解决导致TLE,问题是出在查询无序第k小问题身上,以后在解决无序第K小问题的时候,可以考虑这种算法

  • 相关阅读:
    Codeforces Round #301 (Div. 2) E . Infinite Inversions 树状数组求逆序数
    2017 计蒜之道 初赛 第三场 D. 腾讯狼人杀 (点边都带权的最大密度子图)
    UVALive
    Uvalive 7037 The Problem Needs 3D Arrays(最大密度子图)
    Straight Master Gym-101775J (思维+差分)
    Gym
    Gym 100548F Color 2014-2015 ACM-ICPC, Asia Xian Regional Contest (容斥原理+大数取模)
    牛客国庆集训派对Day3 I.
    HDU
    HDU
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9125908.html
Copyright © 2020-2023  润新知