先离线所有操作 保留所有操作一和三 并求出对应前缀和的级数

所有对i级前缀和[l,r]加val的操作 分为对i级前缀和l加val r+1减val

所有对j级前缀和[l,r]的查询操作 分为对j+1级前缀和r点查询值 减去对j+1级前缀和l-1点查询值

对所有操作三 统计之前的所有更新操作对其的影响即可 复杂度500*n

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll M=998244353;

struct node
{
int tp;
int k;

int pos;
ll val;

int l;
int r;
};

node order[200010];
ll pre[200010],inv[200010];
int n,q,cnt,tot;

ll quickpow(ll a,ll b)
{
ll res;
res=1;
while(b>0)
{
if(b%2) res=(res*a)%M;
a=(a*a)%M,b/=2;
}
return res;
}

void init()
{
ll i;
pre[0]=1,inv[0]=1;
for(i=1;i<=200005;i++)
{
pre[i]=(i*pre[i-1])%M;
inv[i]=quickpow(pre[i],M-2);
}
}

ll getcnk(int nn,int kk)
{
if(kk>nn) return 0;
return (((pre[nn]*inv[kk])%M)*inv[nn-kk])%M;
}

ll gabs(ll x)
{
if(x<0) return -x;
return x;
}


ll solve(int pl,int pr,int k)
{
ll res;
int x,y,i;
res=0;
for(i=1;i<=tot;i++)
{
if(order[i].pos<=pl)
{
x=pl-order[i].pos;
y=k-order[i].k;
ll f=1,fuck=order[i].val;
if(fuck<0)
f=-1;
fuck=gabs(fuck);
res=(res-f*(fuck*getcnk(x+y,x)%M)+M)%M;
}
if(order[i].pos<=pr)
{
x=pr-order[i].pos;
y=k-order[i].k;
ll f=1,fuck=order[i].val;
if(fuck<0)
f=-1;
fuck=gabs(fuck);
res=(res+f*(fuck*getcnk(x+y,x)%M)+M)%M;
}
}
return (res+M)%M;
}

int main()
{
ll val;
int t,i,op,l,r;
init();
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&q);
cnt=0,tot=0;
while(q--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%lld",&l,&r,&val);
tot++;
order[tot].tp=1;
order[tot].k=cnt+1;
order[tot].pos=l;
order[tot].val=val;
tot++;
order[tot].tp=1;
order[tot].k=cnt+1;
order[tot].pos=r+1;
order[tot].val=-val;
}
else if(op==2) cnt++;
else
{
int L,R,K=cnt+1;
scanf("%d%d",&L,&R);
printf("%lld\n",solve(L-1,R,K+1));
}
}
}
return 0;
}