不懂树状数组的童鞋,正好可以通过这道题学习一下树状数组~~百度有很多教程的,我就不赘述了
题意:有三种操作,分别是
1.Push key:将key压入stack
2.Pop:将栈顶元素取出栈
3.PeekMedian:返回stack中第(n+1)/2个小的数
建立一个栈来模拟push和pop,另外还需要树状数组,来统计栈中<=某个数的总个数
不了解树状数组的建议学习一下,很有用的。
树状数组为c,有个虚拟的a数组,a[i]表示i出现的次数
sum(i)就是统计a[1]~a[i]的和,即1~i出现的次数
当我要询问第k个数是多少时,那么我可以通过二分查找来找出第k个数
首先另l=min,r=max,这里min=1,max=100000,mid=(l+r)/2
如果k<=sum(mid),说明1~mid的总个数>=k,则第k个数肯定是在1~mid之间,所以r=mid
如果k>sum(mid),说明1~mid的总个数<k,则第k个数肯定是在mid~r之间,所以l=mid
最后到l与r相邻终止循环
此时如果sum(l)<k && k<=sum(r),说明第k个数即为多个r中的一个
否则的话,说明第k个数为多个l中的一个。
当执行push key的时候,update(key,1),即a[key]++,key出现的次数增加1
当执行pop的时候,update(key,-1),即a[key]--,key出现的次数减少1
#include <iostream> #include <cstdio> #include <algorithm> #include <string.h> #include <map> #include <set> #include <stack> using namespace std; const int maxn=100000+5; int n; int c[maxn]; //树状数组 int lowbit(int x){ return x&(-x); } //树状数组的单点更新操作 void update(int i,int val){ while(i<maxn){ c[i]+=val; i+=lowbit(i); } } //树状数组的区间求和操作 int sum(int i){ int res=0; while(i){ res+=c[i]; i-=lowbit(i); } return res; } int query(int cnt){ //二分查找哪个数是第cnt个大的 int l=1,r=maxn-1; while(l<r-1){ int mid=(l+r)>>1; //<=mid的数有sum(mid)个 if(cnt<=sum(mid)){ r=mid; } else{ l=mid; } } if(sum(l)<cnt && cnt<=sum(r)) return r; else return l; } void test(){ int sizes=7; int a[7]={1,2,2,3,4,4,5}; for(int i=0;i<sizes;i++){ update(a[i],1); } int q; while(scanf("%d",&q)!=EOF){ printf("%d\n",query(q)); } } int main() { char str[15]; memset(c,0,sizeof(c)); //test(); scanf("%d",&n); stack<int>stacks; int cnt=0; int tmp; for(int i=0;i<n;i++){ scanf("%s",str); if(str[1]=='o'){ if(cnt==0) printf("Invalid\n"); else{ tmp=stacks.top(); stacks.pop(); cnt--; update(tmp,-1); printf("%d\n",tmp); } } else if(str[1]=='u'){ scanf("%d",&tmp); stacks.push(tmp); cnt++; update(tmp,1); //printf("%d\n",tmp); } else{ if(cnt==0) printf("Invalid\n"); else{ int idx=(cnt+1)/2; int ans=query(idx); printf("%d\n",ans); } } } return 0; }
来源:https://www.cnblogs.com/chenxiwenruo/p/6765075.html