pat 甲级 1057 Stack

用sort只过得15分
大佬们都用了树状数组
没用树状数组的思路看懂了但是那个语法不会写

树状数组

个人理解:用lowbit把a化成二进制,查零,有k个零的时候,a+k为父亲数组,a-k为上一个是父亲数组的数组

不过题解的代码里没看明白这个是怎么用的。。。迷茫

更新:
树状数组的用法
首先理解好存储方式的图
这里写图片描述

lowbit函数理解:返回数转化为二进制后从末尾开始第一个1
比如: 3 二进制是 0011 lowbit(3)返回 0001
10 二进制是1010 lowbit(10)返回 0010

定义:#define lowbit(i) ((i)&(-i))

求区间和:

int Sum(int x){//前x项的和
    int ANS=0;
    while(x>0){
        ANS+=C[x];
        x-=lowbit(x);
    }
    return ANS;
}

因为数据之间是有关联性的
所以要有更新函数:

void update (int i,int x){  //i点增加x 
    while (i <= N){         //N为原数组长度 
        tree[i] += x;
        i += Lowbit(i);
    }
}

本题中是把数出现的次数存到数组里,不是求数的和↓
用string会超时

#include <cstdio>
#include <iostream>
#include <stack>
#define lowbit(i) ((i)&(-i))

using namespace std;

stack<int> arr;
const int maxn = 100010;
int use[maxn];
int n, sum;
string a = "Push", b = "Pop", c = "PeekMedian"; //用string会超时

void update(int x, int v){
    for(int i = x; i<maxn; i += lowbit(i))
        use[i] += v;

}

int su(int x){
    int fin = 0;
    for(int i=x; i>=1; i -= lowbit(i))
        fin += use[i];
    return fin; 
}

void pek(){
        int left = 1, right = maxn, mid, k = (arr.size()+1)/2;
                while(left < right){
                    mid = (left+right)/2;
                    if(su(mid) >= k) right = mid;
                    else left = mid + 1;
                }
                printf("%d\n",left);
}

int main(){

    scanf("%d",&n);
    for(int i=0; i<n; i++){
        int in;
        char stu[15];
        scanf("%s",&stu);
        if( stu[1]=='u') {
            scanf("%d",&in);
            arr.push(in);
            update(in,1);
            sum++;                      
        }
        else if(stu[1] == 'o') {
            if(sum != 0) {
                printf("%d\n",arr.top());
                update(arr.top(),-1);
                sum--;
                arr.pop();
            }
            else printf("Invalid\n");

        }
        else if(stu[1] == 'e') {
            if(sum != 0)
                pek();          
            else printf("Invalid\n");
        }
    }

    return 0;
}

超时代码↓

#include <cstdio>
#include <iostream>
#include <stack>
#include <algorithm>

using namespace std;

stack<int> arr;
int use[11000];
int n, sum;
string a = "Push", b = "Pop", c = "PeekMedian";

int main(){

    scanf("%d",&n);
    for(int i=0; i<n; i++){
        string v;
        int in;
        cin >> v;
        if( v == a) {
            scanf("%d",&in);
            arr.push(in);
            use[sum] = in;
            sum++;

            //use[sum] = use[sum-1] + in;

        }
        else if(v == b) {
            if(sum != 0) {
                printf("%d\n",arr.top());
                use[sum] = 0;
                sum--;
                arr.pop();
            }
            else printf("Invalid\n");

        }
        else if(v == c) {
            if(sum != 0){
                //int fin = use[(sum+1)/2 ] - use[(sum+1)/2 - 1];
                //sort(use,use+sum);
                //for(int k=0; k<sum; k++) cout << use[k] << " " << k << endl;
                int fin = use[(sum+1)/2-1];
                printf("%d\n",fin);
            }
            else printf("Invalid\n");
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值