#include<bits/stdc++.h>
using namespace std;
#define long long int//不想全改long long 直接宏定义了
vector<int>v;
signed main(){
int n,m,k;
cin>>n>>m>>k;
int k1=-k,k2=k;//表示数轴具体范围在【k1,k2】 之间
while(n--){
int a;
cin>>a;
v.push_back(a);//读入数据存入数组
}
sort(v.begin(),v.end());//排序
int p1=0,p2=v.size()-1;//p1表示数组v还在【k1,k2】之间的第一个元素位置,p2表示还在【k1,k2】之间的最后一个元素位置
while(m--){
int op;
cin>>op;
if(op==1){
int x;
cin>>x;//x表示移动距离
k1=k1-x,k2=k2-x;//数组往正方向移动,等价于k往负方向移动;
if(p2<p1) continue;//如果数组全部在【-k,k】范围,我会使为p1>p2,然后下次判断时直接结束之后的操作;
// 如果数组里还有在【k1,k2】之间的话,那么一定有v【p1】>=k1,v【p2】<=k2;
//下面判断移动之后的三种情况,1、移动的不多,没有数据出去。2、移动的太多,数据全部出去了。3、移动的不多不少,数据一部分出去了。
if(v[p2]<=k2) continue;//第一种情况,不多不少,p1 ,p2都没什么变化。
else if(v[p1]>k2) p2=p1-1; //第二种情况,移动太多,数组全部出去了,此时直接使p2<p1,然后下次判断就直接退出循环,反正已经是0了
else{//第三种情况,移动不多不少,一部分数据出去。
int w=upper_bound(v.begin(),v.end(),k2)-v.begin();//用upper_bound二分查找数组中刚好 > k2的数据
p2=w-1;//那么w的前一项一定是小于等于k2,也就是刚好到k2的前一项它不会被移出去。
}
}
else if(op==2){
int x;
cin>>x;
k1=k1+x,k2=k2+x;//数组往负方向移动,等价于k往正方向移动;
if(p2<p1) continue; //第一种情况,不多不少,p1 ,p2都没什么变化。
if(v[p1]>=k1) continue;
else if(v[p2]<k1) p1=p2+1;//第二种情况,移动太多,数组全部出去了,此时直接使p1>p2,然后下次判断就直接退出循环,反正已经是0了
else{ //第三种情况,移动不多不少,一部分数据出去。
int w=lower_bound(v.begin(),v.end(),k1)-v.begin();//用lower——bound二分查找数组中刚好 >= k1的数据
p1=w;//那么w前面的项是都也就被移出去了,重w开始后面的项就还在【k1,k2】里面。
}
}
else {
if(p1<=p2) cout<<p2-p1+1<<"\n";//输出个数
else cout<<"0\n";//如果p1>p2说明移动途中已经全部都出去过了,输出0
}
}
return 0;
}