PAT 甲级 1057 Stack 分块和树状数组

本文探讨了基数排序中分块统计的方法,指出每次查询通过分块实现复杂度降低到O(N)或O(sqrt(N))。同时,介绍了利用树状数组优化查询效率,达到O(log²N)的时间复杂度。两种技术在解决数据操作问题上的高效应用被详细解析。
摘要由CSDN通过智能技术生成

分块思想

基数排序的原理,并分块统计,每次查询复杂度为 O ( N ) O(\sqrt N ) O(N )

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10,BK=326; // 每个块 sqrt(1e5)=326 个数字
int num[N],arr[N],blocks[N];
int sz=0; // arr 大小 

void Push(){
    cin>>arr[sz];
    num[arr[sz]]++,blocks[arr[sz]/BK]++;
    sz++;
}
void Pop(){
    if(sz==0) cout<<"Invalid\n";
    else{
        num[arr[sz-1]]--,blocks[arr[sz-1]/BK]--;
        cout<<arr[sz-1]<<"\n";
        sz--;
    }
}
void Query(){
    int ctr=0,target=(sz+1)/2;
    int block_id=0;
    while(ctr+blocks[block_id]<target){
        ctr+=blocks[block_id++];
    }
    int beg=BK*block_id;
    while(ctr+num[beg]<target){
        ctr+=num[beg++];
    }
    cout<<beg<<"\n";
}

int main() {
    int n;cin>>n;
    string tmp;
    for(int i=0;i<n;++i){
        cin>>tmp;
        if(tmp=="Pop") Pop();
        else if(tmp=="PeekMedian"){
            if(sz==0) cout<<"Invalid\n";
            else Query();
        }
        else if(tmp=="Push") Push();
    }
}

树状数组

int num[N] 是在基数排序的数组上建立的树状数组,int GetSum(int idx) 返回区间 [ 0 , i d x ] [0,idx] [0,idx] 的和,即小于等于 i d x idx idx 的数字个数。每次查询复杂度为 O ( log ⁡ 2 N ) O(\log^2 N) O(log2N)

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int num[N]; // 树状数组 
stack<int> arr;

int lowbit(int x){return (-x)&x;}
void Add(int idx,int x){
    for(int i=idx;i<N;i+=lowbit(i)){
        num[i]+=x;
    }
}
int GetSum(int idx){
    int ret=0;
    for(int i=idx;i>0;i-=lowbit(i)){
        ret+=num[i];
    }
    return ret;
}
void Query(){
    int k=(arr.size()+1)/2;
    int l=0,r=N; // lower_bound 问题 
    while(l<r){
        int mid=(l+r)/2;
        if(GetSum(mid)<k) l=mid+1;
        else r=mid;
    }
    cout<<l<<"\n";
}

int main() {
    int n;cin>>n;
    string tmp;
    for(int i=0;i<n;++i){
        cin>>tmp;
        if(tmp=="Pop") {
            if(arr.empty()) cout<<"Invalid\n";
            else {
                cout<<arr.top()<<"\n";
                Add(arr.top(),-1);
                arr.pop();
            }
        }
        else if(tmp=="PeekMedian"){
            if(arr.empty()) cout<<"Invalid\n";
            else Query();
        }
        else if(tmp=="Push"){
            int x;cin>>x;
            arr.push(x);
            Add(x,1);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值