hdu 2852

题意 输入0 a 把a压入容器 输入1 a 把a从容器中删除 输入 2 a b 输出大于a的第b个数
两个月前刚开始做题,啥也不会的时候,好像刚自学着搜索,跟着大佬们去上了一节树状数组,那时候居然没有一脸蒙蔽 真是佩服自己,而且后来居然还回去好好看了树状数组的博客,太佩服自己了,现在看着 觉得树状数组的操作比线段树要简单很多。但是如果要用线段树实现树状数组的功能却非常麻烦。树状数组的初始化,更新,求和,用来维护的数组储存的时候每一段区间的和 一个很神奇的东西 #define Lowbit ( (x)&(-x) ) 有了它你就能创建一棵平衡二叉树。每次都是合并同等高度的子树。
使得复杂度降得log(n)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define N 100010
#define Lowbit(x) ((x)&(-x))
int C[N];
bool vis[N];
void add(int x,int num) //加入元素num为1 删除元素 num为-1.
{
    while(x<N)
    {
        C[x]+=num;
        x+=Lowbit(x); //开辟整个树状数组的空间
    }
}
int Sum(int x)
{
    int ans=0;
    while(x>0)
    {
        ans+=C[x];
        x-=Lowbit(x);  //利用树状数组的性质求和。每次都是移位的运算。
    }                  //求的是区间和
    return ans;
}
int binarysearch(int l,int k)
{
    int mid,left,right,tmp;
    left=l+1;   //查找的范围是从 l+1开始的 第k个存在的数
    right=N-1;  //因为树状数组这种方法就是查找整个树状数组这个容器的所有数 所以 右边界是 N-1
    if(Sum(right)-Sum(l)<k) return -1;  //首先判断的是整个树状数组的全部区间的存在个数是否满足 第k个 如果不满足 直接返回-1    

                                     //由于是用数组的下标来存储元素 如果这个元素存在这个容器里面
    while(left<=right)                    //那么vis 就为1 而且 C[x]++;C这个数组下标是元素 存的是元素的个数
    {                                     //再利用二分查找 使得查找降为log n 简直太聪明了
        mid=(left+right)>>1;
        tmp=Sum(mid)-Sum(l);  
        if(tmp==k)  //如果中点到左边界的里面存在数的个数刚刚好 那么就从中点作为右边界开始找就行。
        {
            if(vis[mid])     //如果二分的中点刚好是所求点 那么判断他是否存在就行
                return mid;  //如果不存在 因为 Sum(mid) 找的数肯定不会超过mid 把右边界更新为mid-1
                              //就行 
            right=mid-1;               //这里的二分和我前天晚上做的那个codeforces 很像 虽然我自己做出来了,这里居然没认出来 好丢人呐。。
        }
        else if(tmp>k)
        {                      //如果里面存在的数比要找的多 那么也是首先判断中点是不是
            if(Sum(mid-1)-Sum(l)<k) return mid; //相当于顺便判断了 vis[mid]==1
            right = mid -1;     
        }
        else{
            left=mid+1;        //如果里面存在的数比要找的少 那么肯定不在这个区间 所以把左边界更新为mid+1
        }
    }
    return -1;

}

int main()
{
    int p,n,m,T,e,a,k,l,r,mid;
    while(~scanf("%d",&T))
    {
        memset(C,0,sizeof(C));
        memset(vis,0,sizeof(vis));
        while(T--)
        {
            scanf("%d",&p);
            switch(p)
            {
                case 0:
                scanf("%d",&e);
                add(e,1);   //初始化树状数组
                vis[e]=1;
                break;
                case 1:
                scanf("%d",&e);
                m=Sum(e)-Sum(e-1);
                if(!m) printf("No Elment!\n");
                else add(e,-1);
                if(m==1) vis[e]=0;
                break;
                case 2:
                scanf("%d%d",&a,&k);
                m=binarysearch(a,k);
                if(m==-1)
                    printf("Not Find!\n");
                else
                    printf("%d\n",m);
                break;
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值