分块思想
基数排序的原理,并分块统计,每次查询复杂度为 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);
}
}
}