相关代码内容详见注释,orz
#include <bits/stdc++.h>
#define N 200005
#define ll long long
using namespace std;
ll c,n,len[N],s[N],ma[N],f[N][32];
ll head,tail,down,u;
pair <ll,ll> q[N];
void upd(ll x){
f[tail][0]=x;
for (int i=1;i<=30;i++){
u=tail-(1<<i)+1;
if (u<1){
break;
}
f[u][i]=max(f[u][i-1],f[u+(1<<(i-1))][i-1]);
}
}
ll query(ll l,ll r){
ll k=log2(r-l+1);
return max(f[l][k],f[r-(1<<k)+1][k]);
}
//平平无奇ST表
ll get_pos(ll tail,ll tar){//二分寻找严格大于总长度的块
ll l=1,r=tail,mid,ans=0;
while (l<=r){
mid=(l+r)>>1;
if (s[mid]>=tar){
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
return ans;
}
int main (){
//freopen("queue2.in","r",stdin);
//freopen("queue.out","w",stdout);
ll i,j,op,x,pos,l,r,y;
scanf("%lld%lld",&c,&n);
head=1,tail=0;
for (i=1;i<=n;i++){
scanf("%lld",&op);
if (op==1){//
scanf("%lld",&x);
q[++tail].first=1,q[tail].second=x;//将[1,x]作为一块加入队列
len[tail]=x;//useless
s[tail]=s[tail-1]+len[tail];//块的长度的前缀和
ma[tail]=x;
upd(x);// ST表加入新值
}
if (op==2){
scanf("%lld",&x);
y=x;
pos=get_pos(tail,x+down);//pos是长度为 x的序列重点所在的块的编号
x=s[pos]-down-x;
down+=y;//down是所有已经删去的长度之和
head=pos;
q[pos].first=q[pos].second-x+1;//由终点块往回退更新起点
}
if (op==3){
scanf("%lld",&x);
pos=get_pos(tail,x+down);//pos意义同上
x=s[pos]-down-x;
printf("%lld\n",q[pos].second-x);
}
if (op==4){// 最大值肯定是[1,X]中的 X ,使用ST表,维护在[head,tail] 内的最大值
printf("%lld\n",query(head,tail));
}
}
return 0;
}