#include <bits/stdc++.h>
using namespace std;
typedef long long lolo;
const int MaxN=5e5+5,Mod=(1<<20),Inf=0x3f3f3f3f;
const int snc=5e4+5,bbs=32,dbb=16,dbn=8;
void maxxer(int &x,int &y){x=max(x,y);}
void minner(int &x,int &y){x=min(x,y);}
int frdint(){
int n=0,k=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')k=-1;ch=getchar();}
while(isdigit(ch)){n=(n<<3)+(n<<1)+ch-'0',ch=getchar();}
return n*k;
}
void fwrint(int x){
if(x>9)fwrint(x/10);
putchar(x%10+'0');
}
void fwrlolo(lolo x){
if(x>9)fwrlolo(x/10);
putchar(x%10+'0');
}
int N,M,A[MaxN],Opt,X,Y;lolo Z;
int lb[dbn],rb[dbn],sans,maax,miin;
void traner(int i);
struct SegmentTree{
int mx[snc],mn[snc],cnt[snc];
int id;lolo tag[snc],sum[snc];
int ls(int p){return p<<1;}
int rs(int p){return (p<<1)|1;}
void init(int i){
lb[i]=(i==0?1:rb[i-1]+1);
rb[i]=lb[i]*dbb-1;id=i;
memset(tag,0,sizeof(tag));
memset(mx,0,sizeof(mx));
memset(mn,0x3f,sizeof(mn));
memset(cnt,0,sizeof(cnt));
memset(sum,0,sizeof(sum));
//初始化
}
void pushup(int p){
cnt[p]=cnt[ls(p)]+cnt[rs(p)];
sum[p]=sum[ls(p)]+sum[rs(p)];
mx[p]=max(mx[ls(p)],mx[rs(p)]);
mn[p]=min(mn[ls(p)],mn[rs(p)]);
}//显然。
void maketag(int p,lolo &val){
tag[p]+=val,sum[p]-=val*cnt[p];
mx[p]-=val,mn[p]-=val;
}//显然。
void pushdown(int p){
if(!tag[p])return;
if(cnt[ls(p)])maketag(ls(p),tag[p]);
if(cnt[rs(p)])maketag(rs(p),tag[p]);
tag[p]=0;
}//显然。
void bushup(int p,int cl,int cr){
cnt[p]=0,sum[p]=0,mx[p]=0,mn[p]=Inf;
for(int i = cl;i <= cr;i++){
if(A[i]>=lb[id]&&A[i]<=rb[id]){
cnt[p]++,sum[p]+=A[i];
maxxer(mx[p],A[i]),minner(mn[p],A[i]);
}
}
}
//块上传
void bushdown(int cl,int cr,lolo &val){
if(!val)return;
for(int i = cl;i <= cr;i++){
if(A[i]>=lb[id]&&A[i]<=rb[id])A[i]-=val;
}
val=0;
}
//块下传
void insert(int p,int cl,int cr,int dd,int val){
if(cr-cl+1<=bbs){
bushdown(cl,cr,tag[p]);A[dd]=val;
bushup(p,cl,cr);return;
}
int mid=(cl+cr)>>1;pushdown(p);
if(dd<=mid)insert(ls(p),cl,mid,dd,val);
if(dd>mid)insert(rs(p),mid+1,cr,dd,val);
pushup(p);
}
//往线段树里加入新值
void ubdate(int cl,int cr,int x){
for(int i = cl;i <= cr;i++){
if(A[i]>=lb[id]&&A[i]<=rb[id]&&A[i]>x){
A[i]-=x;if(A[i]<lb[i])traner(i);
}
}
}
//块内更新
void buery(int cl,int cr,int dl,int dr){
for(int i = max(cl,dl);i <= min(cr,dr);i++){
if(A[i]>=lb[id]&&A[i]<=rb[id]){
sans+=A[i],maxxer(maax,A[i]),minner(miin,A[i]);
}
}
}
//块上询问
void update(int p,int cl,int cr,int dl,int dr,lolo val){
if(mx[p]<=val)return;
if(cr-cl+1<=bbs){
bushdown(cl,cr,tag[p]);
maxxer(dl,cl),minner(dr,cr);
ubdate(dl,dr,val);bushup(p,cl,cr);
return;
}
if(dl<=cl&&cr<=dr&&mn[p]-lb[id]>=val){
maketag(p,val);return;
}
int mid=(cl+cr)>>1;pushdown(p);
if(cl<=mid)update(ls(p),cl,mid,dl,dr,val);
if(cr>mid)update(rs(p),mid+1,cr,dl,dr,val);
pushup(p);
}
//更新
void query(int p,int cl,int cr,int dl,int dr){
if(dl<=cl&&cr<=dr){
maxxer(maax,mx[p]),minner(miin,mn[p]);
sans+=sum[p];return;
}
if(cr-cl+1<=bbs){
bushdown(cl,cr,tag[p]);
buery(cl,cr,dl,cr);
bushup(p,cl,cr);return;
}
int mid=(cl+cr)>>1;pushdown(p);
if(dl<=mid)query(ls(p),cl,mid,dl,dr);
if(dr>mid)query(rs(p),mid+1,cr,dl,dr);
pushup(p);
}
//询问
}SegTr[dbn];//一棵线段树对应一块倍增块
int getblk(int x){
int cur=0;
while(x>rb[cur])cur++;
return cur;
}
//找值对应的块
void traner(int i){SegTr[getblk(A[i])].insert(1,1,N,i,A[i]);}
//由于我把每个倍增块的线段树分开了,所以我需要一个函数去把这个值跌到下一个块。
void psp(){putchar(' ');}//打印一个空格
int main(){
// freopen("smp1.in","r",stdin);
// freopen("myans1.out","w",stdout);
N=frdint(),M=frdint();
for(int i = 0;i < dbn;i++)SegTr[i].init(i);
for(int i = 1;i <= N;i++){
A[i]=frdint();SegTr[getblk(A[i])].insert(1,1,N,i,A[i]);
}
while(M--){
Opt=frdint(),X=frdint()^sans,Y=frdint()^sans;
if(Opt==1){
Z=frdint()^sans;for(int i = 0;i < dbn;i++){
if(rb[i]>=Z)SegTr[i].update(1,1,N,X,Y,Z);
}
}
if(Opt==2){
sans=0,maax=0,miin=Inf;
for(int i = 0;i < dbn;i++)SegTr[i].query(1,1,N,X,Y);
// putchar('x');
fwrlolo(sans),psp(),fwrint(miin),psp(),fwrint(maax);
puts("");sans%=Mod;
}
}
return 0;
}
较多借鉴了这位奆佬的题解,马蜂良好而精悍,去掉注释只有153行。若调试出来,玄2关注。