1. 程式人生 > >HDU2852【樹狀陣列+二分】

HDU2852【樹狀陣列+二分】

額。。有點遺忘了樹狀陣列特性了。。印象中一直是字首和,然後一定要記住樹狀陣列是把給出的值(值太大可能可以離散化)也就是點到了區間,然後這個點存的值就是由自己來定了。
題意:
百度。

思路:
樹狀陣列是用來標記的!值->區間點!
因為這裡值重複是算的,所有樹狀陣列存的是區間上該位置的個數。
0:插入則插入。
1:if(!(sum[x]-sum[x-1])) puts("NO...");
2:我們知道a(包括a)之前有多少個數x,求第k大的數,也就是求在樹狀陣列中第x+k大的數。
sum[ans]=x+k。這個可以直接二分查詢。

---

哦,還可以線段樹,還是一樣的,值->區間點,點所存的值自己定,這裡也就是個數,差不多。但是這個查詢第k大的數的位置,麻煩了。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=1e5+10;
int c[N],m;

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

void add(int x,int val)
{
    while(x<=100000)
    {
        c[x]+=val;
        x+=lowbit(x);
    }
}

int sum(int x)
{
    int ans=0;
    while(x>0)
    {
        ans+=c[x];
        x-=lowbit(x);
    }
    return ans;
}

int main()
{
    while(~scanf("%d",&m))
    {
        int x;
        int a,k;
        memset(c,0,sizeof(c));
        while(m--)
        {
            scanf("%d",&x);
            if(x==0)
            {
                scanf("%d",&a);
                add(a,1);
            }
            else if(x==1)
            {
                scanf("%d",&a);
                if(sum(a)-sum(a-1)==0)
                    puts("No Elment!");
                else
                    add(a,-1);
            }
            else
            {
                scanf("%d%d",&a,&k);
                int p=sum(a)+k;
                int left=1,right=100000;
                while(left<right)
                {
                    int mid=left+(right-left)/2;
                    if(sum(mid)>=p)
                        right=mid;
                    else
                        left=mid+1;
                }
                if(sum(left)>=p)
                    printf("%d\n",left);
                else
                    puts("Not Find!");
            }
        }
    }
    return 0;
}