Sample Input:
17
Pop
PeekMedian
Push 3
PeekMedian
Push 2
PeekMedian
Push 1
PeekMedian
Pop
Pop
Push 5
Push 4
PeekMedian
Pop
Pop
Pop
Pop
Sample Output:
Invalid
Invalid
3
2
2
1
2
4
4
5
3
Invalid
题目大意
模拟栈的基本操作,但是加上一个功能:返回栈里第mid大的数。
对于n个数。
如果n为偶,则mid=n/2;如果n为奇,则mid=(n+1)/2
分析
首先,mid=(n+1)/2。
这道题如果用排序+查找,会超时。中间三个点过不去。
看到晴神书里的做法,才想起来索引(分块)查找。
- 因为最大的key仅为1e5级别,不是很大,所以可以直接开一个Hash[1e5+1]的数组,用来存放key的个数。
- 进行分块。总共有sqrt(1e5+1)+1,每个块存sqrt(1e5+1)+1个数。即,总共有317个块,每个块存317个数。创建一个block[317]来保存每个分块里有多少个数。
- 每次push时候,都需要增加Hash和block数组里的数;每次pop也是
- 求mid的时候只需要找到对应的块,然后再累加找到第mid个数即可
#include <cstdio> #include <iostream> #include <stack> #include <cstring> #include <cmath> using namespace std; const int maxn=1e5+1; int Hash[maxn]; int n,mod=sqrt(maxn)+1,tmp,chu,yu; int block[317]; stack<int> st; void init(){ memset(Hash,0,sizeof(Hash)); memset(block,0,sizeof(block)); } void GetPeekMid(){ if(st.size()==0) { cout << "Invalid" <<"\n"; return ; } int mid=(st.size()+1)/2; int sum=0,i; for(int j=1;j<=mod && sum<mid;++j){ sum+=block[j]; i=j; } sum-=block[i]; for(int j=(i-1)*mod;j<i*mod;j++){ for(int k=0;k<Hash[j];k++){ sum++; if(sum==mid){ cout << j <<"\n"; return ; } } } } int main(){ cin >> n; init(); for(int i=0;i<n;++i){ string s; cin >> s; if(s[1]=='o'){ if(!st.empty()){ tmp=st.top(); cout << tmp <<"\n"; st.pop(); chu=tmp/mod+1; Hash[tmp]--; block[chu]--; }else{ cout << "Invalid" <<"\n"; } }else if(s[1]=='u'){ cin >> tmp; st.push(tmp); chu=tmp/mod+1; block[chu]++; Hash[tmp]++; }else{ GetPeekMid(); } } return 0; }
这个代码可能可以再快一些,主要是因为我是累加求sum的,所以差一点超时。
除了分块查找以外,找到第k大也可以用树状数组。
#include <bits/stdc++.h> using namespace std; const int N=1e5+1; int c[N],a[N]; int n,top=0; int lowbit(int x){ return x&(-x); } void update(int x,int v){ for(int i=x;i<=N;i+=lowbit(i)){ c[i]+=v; } } int getSum(int x){ int sum=0; for(int i=x;i>0;i-=lowbit(i)){ sum+=c[i]; } return sum; } int halfSearch(int x){ int l=1,r=N; while(l<r){ int mid=(l+r)/2; if(getSum(mid)>=x) r=mid; else l=mid+1; } return r; } int main() { cin >> n; for(int i=0; i<n; ++i) { string s; cin >> s; if(s[1]=='o') { if(top>0){ update(a[top],-1); cout << a[top--] <<"\n"; }else{ cout << "Invalid" <<"\n"; } } else if(s[1]=='u') { cin >> a[++top]; update(a[top],1); } else { int mid=(top+1)/2; if(mid<1) cout << "Invalid" <<"\n"; else cout << halfSearch(mid) <<"\n"; } } return 0; }