HDU - 2852 - KiKi's K-Number(树状数组)

KiKi's K-Number

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4158    Accepted Submission(s): 1875


Problem Description
For the k-th number, we all should be very familiar with it. Of course,to kiki it is also simple. Now Kiki meets a very similar problem, kiki wants to design a container, the container is to support the three operations.

Push: Push a given element e to container

Pop: Pop element of a given e from container

Query: Given two elements a and k, query the kth larger number which greater than a in container;

Although Kiki is very intelligent, she can not think of how to do it, can you help her to solve this problem?
 

Input
Input some groups of test data ,each test data the first number is an integer m (1 <= m <100000), means that the number of operation to do. The next m lines, each line will be an integer p at the beginning, p which has three values:
If p is 0, then there will be an integer e (0 <e <100000), means press element e into Container.

If p is 1, then there will be an integer e (0 <e <100000), indicated that delete the element e from the container  

If p is 2, then there will be two integers a and k (0 <a <100000, 0 <k <10000),means the inquiries, the element is greater than a, and the k-th larger number.
 

Output
For each deletion, if you want to delete the element which does not exist, the output "No Elment!". For each query, output the suitable answers in line .if the number does not exist, the output "Not Find!". 
 

Sample Input
  
  
5 0 5 1 2 0 6 2 3 2 2 8 1 7 0 2 0 2 0 4 2 1 1 2 1 2 2 1 3 2 1 4
 

Sample Output
  
  
No Elment! 6 Not Find! 2 2 4 Not Find!
 

Source
 

题意:
有一种容器,有三种操作:

1、在容器中加入一个值为e的数(p = 0)

2、从容器中取出一个值为e的数,若容器内不存在值为e的数,则输出"No Elment!" (p = 1)

3、在容器中找出比值为a大的第k个数并输出,若不存在,则输出"Not Find!"(p = 2)

主要就是插入删除和查找三个操作

然后就是有n个操作,按题目要求执行

思路:
由树状数组可以快速得到各个区间的和,也就是说可以快速得到[1,n]区间内有几个数,然后题目要求的是比a大的第k个数m,就是说[1,m]区间的数的数量要比[1,a]区间内的多k个,然后一个数可以出现多次,所以要满足A[1,m]>=k,A[1,m-1]<k,就可以先建树状数组,然后二分查找,因为是一个区间的问题,所以刚开始二分有些地方写的有点问题,没有考虑到这个范围什么的

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int maxn = 100000 + 100;
int n,p,e,a,k,num[maxn],sum[maxn],cnt;//num数组用来记录每值有几个数,sum数组就是对应的树状数组
int lowbit(int x)
{
    return x&-x;
}
void add_and_sub(int pos,int n)
{
    while(pos<maxn)
    {
        sum[pos] += n;
        pos += lowbit(pos);
    }
}
int Sum(int pos)
{
    int ans = 0;
    while(pos>0)
    {
        ans+=sum[pos];
        pos-=lowbit(pos);
    }
    return ans;
}
int find(int be,int k)//这里的k就是[1,m]里要有的数的个数
{
    int l = be + 1,r = maxn-1,mid = (l+r)/2;
    while(l<=r)
    {
        mid = (l+r)/2;
        int sum_mid = Sum(mid);//[1,mid]内有几个数
        if(sum_mid>=k)
        {
            r = mid - 1;
            if(sum_mid-num[mid]<k)//sum_mid-num[mid] = sum(mid-1)
                return mid;
        }
        else if(sum_mid<k)
            l = mid + 1;
    }
    return mid;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        memset(sum,0,sizeof sum);
        memset(num,0,sizeof num);
        cnt = 0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&p);
            if(p==2)
            {
                scanf("%d%d",&a,&k);
                int low = Sum(a);//小于等于a的数的个数
                if(cnt-low<k)//cnt-low = 大于a的数的个数
                    printf("Not Find!\n");
                else
                    printf("%d\n",find(a,low+k));
            }
            else
            {
                scanf("%d",&e);
                if(p==0)
                {
                    num[e]++,cnt++;
                    add_and_sub(e, 1);
                }
                else
                {
                    if(num[e]==0)
                        printf("No Elment!\n");
                    else
                    {
                        add_and_sub(e, -1);
                        num[e]--,cnt--;
                    }
                }
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值