L3-002 特殊堆栈 (30分) 权值线段树求第k大
堆栈是一种经典的后进先出的线性结构,相关的操作主要有“入栈”(在堆栈顶插入一个元素)和“出栈”(将栈顶元素返回并从堆栈中删除)。本题要求你实现另一个附加的操作:“取中值”——即返回所有堆栈中元素键值的中值。给定 N 个元素,如果 N 是偶数,则中值定义为第 N/2 小元;若是奇数,则为第 (N+1)/2 小元。
输入格式:
输入的第一行是正整数 N(≤)。随后 N 行,每行给出一句指令,为以下 3 种之一:
Push key
Pop
PeekMedian
其中 key
是不超过 1 的正整数;Push
表示“入栈”;Pop
表示“出栈”;PeekMedian
表示“取中值”。
输出格式:
对每个 Push
操作,将 key
插入堆栈,无需输出;对每个 Pop
或 PeekMedian
操作,在一行中输出相应的返回值。若操作非法,则对应输出 Invalid
。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 string tmp; 5 stack<int>S; 6 struct node 7 { 8 int ln,rn; 9 int sum; 10 }tree[maxn<<4]; 11 void build(int l,int r,int root) 12 { 13 tree[root].ln=l;tree[root].rn=r;tree[root].sum=0; 14 if(l==r){ 15 return ; 16 } 17 int mid=l+r>>1; 18 build(l,mid,root<<1); 19 build(mid+1,r,root<<1|1); 20 } 21 void update(int pos,int val,int root) 22 { 23 int l=tree[root].ln; 24 int r=tree[root].rn; 25 // printf("haha: %d %d\n",l,r); 26 if(l==r){ 27 // printf("l:%d\n",l); 28 tree[root].sum+=val; 29 return; 30 } 31 int mid=l+r>>1; 32 if(pos<=mid) update(pos,val,root<<1); 33 else update(pos,val,root<<1|1); 34 tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum; 35 } 36 int query(int root,int k) 37 { 38 int l=tree[root].ln; 39 int r=tree[root].rn; 40 if(l==r) return l; 41 int ans; 42 if(tree[root<<1].sum>=k) ans=query(root<<1,k); 43 else ans=query(root<<1|1,k-tree[root<<1].sum); 44 return ans; 45 } 46 int main() 47 { 48 build(1,maxn-10,1); 49 int n; 50 scanf("%d",&n); 51 for(int i=1;i<=n;i++){ 52 cin>>tmp; 53 if(tmp=="Push"){ 54 int val; 55 scanf("%d",&val); 56 S.push(val); 57 update(val,1,1); 58 } 59 else if(tmp=="PeekMedian"){ 60 if(S.size()==0) printf("Invalid\n"); 61 else{ 62 int k=(S.size()+1)/2; 63 printf("%d\n",query(1,k)); 64 } 65 } 66 else if(tmp=="Pop"){ 67 if(S.size()==0) printf("Invalid\n"); 68 else{ 69 int val=S.top(); 70 S.pop(); 71 printf("%d\n",val); 72 update(val,-1,1); 73 } 74 } 75 } 76 }