• PAT1057 Stack(树状数组+倍增)


    题目大意

    要求维护一个栈,提供压栈、弹栈以及求栈内中位数的操作(当栈内元素(n)为偶数时,只是求第(n/2)个元素而非中间两数的平均值)。最多操作100000次,压栈的数字(key)范围是[1,100000]。

    题目分析

    前两个操作用(stack)就好。

    求中位数。暴力做法即使用上优先队列也是稳稳的超时。考虑树状数组。

    压栈时,将(key)值对应的位置加1。弹栈减1。

    求中位数,可以二分求出(sum[1:p]==(n+1)/2)最小的(p),即为(ans)。复杂度(O(nlog^2n))

    问题已被解决,但是还有进一步优化的空间。

    考虑倍增(?)。从高到低枚举(ans-1)的每一个二进制位,即求最大的(p)使得(sum[1:p]<(n+1)/2)。我们知道树状数组(tree[k]=sum_{i=k-lowbit(k)+1}^knum[i]),也就是说如果我们知道(sum_{i=1}^knum[i]=A)((1<<j)<lowbit(k)),那么(sum_{i=1}^{k+(1<<j)}=A+tree[k+(1<<j)])。倍增的时候枚举二进制位的时候,恰巧我们也是从大到小枚举的,满足(j)(k)的限制。这样,就将一次树状数组上(logn)的查询替换成一次简单的加法。复杂度(O(nlogn))

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int num;
    
    stack<int> st;
    
    int sum[100005];
    
    int lowbit(int x) {return x & -x;}
    
    void add(int p, int v) {for (int i = p; i <= 100000; i += lowbit(i)) sum[i] += v;}
    
    /*
    int get(int p) {
        int ret = 0;
        for (int i = p; i >= 1; i -= lowbit(i)) ret += sum[i];
        return ret;
    }
    */
    
    int main() {
        num = 0;
        while (!st.empty()) st.pop();
        memset(sum, 0, sizeof(sum));
    
        int n;
        scanf("%d", &n);
        for (int _ = 0; _ < n; ++_) {
            char com[20];
            scanf("%s", com);
            if (strcmp(com, "Push") == 0) {
                int key;
                scanf("%d", &key);
                ++num;
                st.push(key);
                add(key, 1);
            } else if (strcmp(com, "Pop") == 0) {
                if (!st.empty()) {
                    int key = st.top();
                    printf("%d
    ", key);
                    --num;
                    st.pop();
                    add(key, -1);
                } else printf("Invalid
    ");
            } else {
                if (!st.empty()) {
                    int temp = 0, ans = 0;
                    for (int i = 16; i >= 0; --i) {
                        if (ans + (1 << i) > 100000) continue;
                        if (temp + sum[ans + (1 << i)] < (num + 1) / 2) temp += sum[ans += (1 << i)];
                    }
                    printf("%d
    ", ans + 1);
                } else printf("Invalid
    ");
            }
        }
        return 0;
    }
    
  • 相关阅读:
    函数的对象
    函数的调用
    函数的参数
    函数的返回值
    定义函数的三种方式
    网络的瓶颈效应
    编程语言分类
    计算机操作系统
    【建议收藏】2020最全阿里,腾讯,美团面试题总结(附答案整理)
    建议收藏!2020阿里面试题(JVM+Spring Cloud+微服务)上
  • 原文地址:https://www.cnblogs.com/acboyty/p/12074646.html
Copyright © 2020-2023  润新知