#include<iostream>
using namespace std;
const int N=100010;
int h[N], hp[N], ph[N] ,cnt; //hp[]表示堆中(h[])每个位置的元素是第几个插入的,ph[]表示第几个插入的元素在h[]中的位置, cnt表示当前堆元素个数
void heap_swap(int a, int b){
swap(h[a], h[b]);
swap(ph[hp[a]], ph[hp[b]]); //先根据堆中位置找到插入次序,先交换ph 再交换hp,否则交换Hp后无法找到正确的Ph
swap(hp[a], hp[b]);
}
void down(int x){
int t=x;
if(x*2<=cnt && h[x*2]<h[t]) t=2*x; //注意t和x的位置不能随意调换
if(x*2+1<=cnt && h[x*2+1]<h[t]) t=x*2+1;
if(t!=x) {
heap_swap(x, t);
down(t);
}
}
void up(int x){
int t=x;
if(x/2>0 && h[x/2]>h[x]) t=x/2;
if(t!=x){
heap_swap(x, t);
up(t);
}
}
int main(){
int n, m=0; //m表示当前插入次数
cin >>n;
while(n--){
char op[5];
scanf("%s", op);
if(op[0]=='I'){
int x;
scanf("%d", &x);
cnt++, m++;
h[cnt]=x;
ph[m]=cnt; //第m个插入的数在堆中的下标为cnt
hp[cnt]=m; //堆中下标为cnt的数是第m个插入的
up(cnt);
}else if(op[0]=='P'){
printf("%d\n", h[1]);//打印堆顶
}else if(op[0]=='C'){
int k, x; //将第k个插入的数变成x
scanf("%d%d", &k, &x);
k = ph[k]; //将k从次序映射为在堆中的下标
h[k]=x;
down(k), up(k);
}else{ //"D"
if(op[1]=='M'){ //"DM" 删除最小值
heap_swap(1, cnt);
cnt--;
down(1);
}else{ //"D" 删除第k个插入的数
int k;
scanf("%d", &k);
k=ph[k];//映射为下标
heap_swap(k, cnt);
cnt--;
down(k), up(k);
}
}
}
return 0;
}