绫地宁宁天下第一!
考虑对于每一个块,用一个来维护每次整块的覆盖
对于每个点再维护一个表示对散块的覆盖
将块内每个点按照最后一次覆盖的时间排序
维护一下后缀和
对于询问,散块暴力加
整块二分找到第一个在整块覆盖后被修改的点
前面所有答案就都是整块的答案,加上后缀和即可
每次覆盖整块加进去,散块重构
每次撤销直接删去那次覆盖,散块重构
这样可以做到
考虑实际上每次加入的时间都是单调的
所以维护一个栈就可以了
对于每次重构,可以利用基数排序
由于保证赋值不超过
可以用基排
二分可以每次重构的时候维护一个指针指向第一个小于整块覆盖的点
由于有撤销
每次重构的时候维护一下当前时间
每次询问的时候将当前时间和上次重构比较
如果在重构之前就暴力跳指针就可以了
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cs const
#define bg begin
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=100005,S=251,M=255;
char x;
int del[N],n,m,tot;
namespace Stk{
int cnt,adj[N],nxt[N*(S+14)],to[N*(S+14)];
inline void push(int u,int v){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
}
inline int front(int x){
return to[adj[x]];
}
inline void pop(int x){
while(del[to[adj[x]]])adj[x]=nxt[adj[x]];
}
}
using Stk::pop;
using Stk::front;
using Stk::push;
int bel[N],L[N],R[N],pos[N];
struct opt{
int l,r,v;
}q[N];
struct block{
static cs int S=::S+10;
int pos,siz,pt,last;
int val[S],a[S],stk[N],top;
ll sum[S],s;
inline ll Sort(){
static int buc[S],rk[S];
ll res=0;
for(int i=1;i<=siz;i++)val[i]=front(i+pos),res+=(val[i]?0:a[i]);
for(int i=0;i<=M;i++)buc[i]=0;
for(int i=1;i<=siz;i++)buc[val[i]&M]++;
for(int i=1;i<=M;i++)buc[i]+=buc[i-1];
for(int i=siz;i;i--)rk[buc[val[i]&M]--]=val[i];
for(int i=0;i<=M;i++)buc[i]=0;
for(int i=1;i<=siz;i++)buc[val[i]>>8]++;
for(int i=1;i<=M;i++)buc[i]+=buc[i-1];
for(int i=siz;i;i--)val[buc[rk[i]>>8]--]=rk[i];
return res;
}
inline void build(){
s=0;
for(int i=1;i<=siz;i++)s+=a[i];
sum[0]=s;
}
inline void rebuild(){
ll res=Sort();last=stk[top];
for(int i=siz-1;~i;i--)sum[i]=sum[i+1]+q[val[i+1]].v;sum[0]+=res;
pt=0;
while(pt<siz&&val[pt+1]<last)pt++;
s=sum[pt]+1ll*pt*q[last].v;
}
inline void insert(int x){
stk[++top]=x,s=1ll*q[x].v*siz;
}
inline void reset(){
while(del[stk[top]])top--;
if(stk[top]<=last){
while(pt&&val[pt]>=stk[top])pt--;
s=sum[pt]+1ll*pt*q[stk[top]].v;
}
else s=1ll*q[stk[top]].v*siz;
}
inline ll query(int l,int r){
ll res=0;
int t=stk[top];
if(t)for(int i=l;i<=r;i++)res+=(front(i)<t)?q[t].v:q[front(i)].v;
else for(int i=l;i<=r;i++)res+=(front(i)?q[front(i)].v:a[i-pos]);
return res;
}
}A[N/S+5];
char y;
inline void update(int l,int r,int v){
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++)push(i,v);
A[bel[l]].rebuild();return;
}
for(int i=l;i<=R[bel[l]];i++)push(i,v);
A[bel[l]].rebuild();
for(int i=L[bel[r]];i<=r;i++)push(i,v);
A[bel[r]].rebuild();
for(int i=bel[l]+1;i<bel[r];i++)A[i].insert(v);
}
inline void delet(int l,int r){
if(bel[l]==bel[r]){
for(int i=l;i<=r;i++)pop(i);
A[bel[l]].rebuild();return;
}
for(int i=l;i<=R[bel[l]];i++)pop(i);
A[bel[l]].rebuild();
for(int i=L[bel[r]];i<=r;i++)pop(i);
A[bel[r]].rebuild();
for(int i=bel[l]+1;i<bel[r];i++)A[i].reset();
}
inline ll query(int l,int r){
if(bel[l]==bel[r])return A[bel[l]].query(l,r);
ll res=0;
res+=A[bel[l]].query(l,R[bel[l]]);
res+=A[bel[r]].query(L[bel[r]],r);
for(int i=bel[l]+1;i<bel[r];i++)res+=A[i].s;
return res;
}
ll last;
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++)bel[i]=(i-1)/S+1;
for(int i=1;i<=n;i++)A[bel[i]].a[(i-1)%S+1]=read();
for(int i=1;i<=bel[n];i++)L[i]=(i-1)*S+1,R[i]=i*S;
R[bel[n]]=n;
for(int i=1;i<=bel[n];i++)A[i].pos=L[i]-1;
for(int i=1;i<=n;i++)A[bel[i]].siz=i-L[bel[i]]+1;
for(int i=1;i<=bel[n];i++)A[i].build();
while(m--){
int op=read();
if(op==1){
int l=read()^last,r=read()^last,v=read();
q[++tot]=opt{l,r,v};
update(l,r,tot);
}
else if(op==2){
int l=read()^last,r=read()^last;
cout<<(last=query(l,r))<<'
';
}
else{
int x=read()^last;
del[x]=1;
delet(q[x].l,q[x].r);
}
}
}