题目:https://www.patest.cn/contests/gplt
思路:
线段树求第k小
第一次这样使用线段树,从1到最大建树,把每个数放到叶节点里,每放一个就++,这样就相当于排好序了,查找x时找节点的cnt值就行,这样找到的就是第x小,然后把值输出即可(left或right)
第一次发现不能t<<1+1这么写,只能t<<1|1。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
struct node{
int l,r,cnt;
}tree[4*maxn];
stack<int> A;
void build(int l,int r,int t){
tree[t].l=l;
tree[t].r=r;
tree[t].cnt=0;
if(l==r)
return ;
int mid=(l+r)>>1;
build(l,mid,t<<1);
build(mid+1,r,t<<1|1);
tree[t].cnt=tree[t<<1].cnt+tree[t<<1|1].cnt;
}
void update(int t,int x,int val){
if(tree[t].l==tree[t].r&&tree[t].l==x){
tree[t].cnt+=val;
return;
}
int mid=(tree[t].l+tree[t].r)>>1;
if(x<=mid)
update(t<<1,x,val);
else
update(t<<1|1,x,val);
tree[t].cnt=tree[t<<1].cnt+tree[t<<1|1].cnt;
}
int query(int t,int k){
if(tree[t].l==tree[t].r){
return tree[t].l;
}
if(k<=tree[t<<1].cnt)
return query(t<<1,k);
else
return query(t<<1|1,k-tree[t<<1].cnt);
}
int main(){
int n;
char ch[20];
scanf("%d",&n);
while(!A.empty()) A.pop();
build(1,maxn-5,1);
while(n--){
scanf("%s",ch);
if(!strcmp(ch,"Pop")){
if(A.empty()) puts("Invalid");
else{
int tt=A.top();
A.pop();
printf("%d\n",tt);
update(1,tt,-1);
}
}
else if(!strcmp(ch,"Push")){
int x;
scanf("%d",&x);
A.push(x);
update(1,x,1);
}
else if(!strcmp(ch,"PeekMedian")){
if(A.empty()) puts("Invalid");
else{
int sz=A.size();
if(sz%2) sz=(sz+1)/2;
else sz=sz/2;
printf("%d\n",query(1,sz));
}
}
}
return 0;
}