zoukankan      html  css  js  c++  java
  • PAT甲级题解-1057. Stack (30)-树状数组

    不懂树状数组的童鞋,正好可以通过这道题学习一下树状数组~~百度有很多教程的,我就不赘述了


    题意:有三种操作,分别是
    1.Push key:将key压入stack
    2.Pop:将栈顶元素取出栈
    3.PeekMedian:返回stack中第(n+1)/2个小的数

    建立一个栈来模拟push和pop,另外还需要树状数组,来统计栈中<=某个数的总个数
    不了解树状数组的建议学习一下,很有用的。
    树状数组为c,有个虚拟的a数组,a[i]表示i出现的次数
    sum(i)就是统计a[1]~a[i]的和,即1~i出现的次数
    当我要询问第k个数是多少时,那么我可以通过二分查找来找出第k个数
    首先另l=min,r=max,这里min=1,max=100000,mid=(l+r)/2
    如果k<=sum(mid),说明1~mid的总个数>=k,则第k个数肯定是在1~mid之间,所以r=mid
    如果k>sum(mid),说明1~mid的总个数<k,则第k个数肯定是在mid~r之间,所以l=mid
    最后到l与r相邻终止循环
    此时如果sum(l)<k && k<=sum(r),说明第k个数即为多个r中的一个
    否则的话,说明第k个数为多个l中的一个。

    当执行push key的时候,update(key,1),即a[key]++,key出现的次数增加1
    当执行pop的时候,update(key,-1),即a[key]--,key出现的次数减少1

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <string.h>
    #include <map>
    #include <set>
    #include <stack>
    using namespace std;
    const int maxn=100000+5;
    int n;
    int c[maxn]; //树状数组
    int lowbit(int x){
        return x&(-x);
    }
    //树状数组的单点更新操作
    void update(int i,int val){
        while(i<maxn){
            c[i]+=val;
            i+=lowbit(i);
        }
    }
    //树状数组的区间求和操作
    int sum(int i){
        int res=0;
        while(i){
            res+=c[i];
            i-=lowbit(i);
        }
        return res;
    }
    
    int query(int cnt){
        //二分查找哪个数是第cnt个大的
        int l=1,r=maxn-1;
        while(l<r-1){
            int mid=(l+r)>>1;
            //<=mid的数有sum(mid)个
            if(cnt<=sum(mid)){
                r=mid;
            }
            else{
                l=mid;
            }
        }
        if(sum(l)<cnt && cnt<=sum(r))
            return r;
        else
            return l;
    }
    void test(){
        int sizes=7;
        int a[7]={1,2,2,3,4,4,5};
        for(int i=0;i<sizes;i++){
            update(a[i],1);
        }
        int q;
        while(scanf("%d",&q)!=EOF){
            printf("%d
    ",query(q));
        }
    }
    int main()
    {
        char str[15];
        memset(c,0,sizeof(c));
        //test();
        scanf("%d",&n);
        stack<int>stacks;
        int cnt=0;
        int tmp;
        for(int i=0;i<n;i++){
            scanf("%s",str);
            if(str[1]=='o'){
                if(cnt==0)
                    printf("Invalid
    ");
                else{
                    tmp=stacks.top();
                    stacks.pop();
                    cnt--;
                    update(tmp,-1);
                    printf("%d
    ",tmp);
                }
            }
            else if(str[1]=='u'){
                scanf("%d",&tmp);
                stacks.push(tmp);
                cnt++;
                update(tmp,1);
                //printf("%d
    ",tmp);
            }
            else{
                if(cnt==0)
                    printf("Invalid
    ");
                else{
                    int idx=(cnt+1)/2;
                    int ans=query(idx);
                    printf("%d
    ",ans);
                }
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Arraylist和Linkedlist的区别
    list和map的区别
    collection和collections区别
    Linux操作命令(六)
    Linux操作命令(五)
    Linux操作命令(四)
    Linux操作命令(三)
    Linux操作命令(二)
    Linux操作命令(一)
    ProgrammingProjectList-文本操作
  • 原文地址:https://www.cnblogs.com/chenxiwenruo/p/6765075.html
Copyright © 2011-2022 走看看