由于其中的2操作非常多,我们就需要将其快速的更改,就会用到组合数的东西
其实自己手写一下就可以发现对于一个点增加的值在经过不断地前缀和累加过程中对于一点的贡献满足杨辉三角
所以我们就需要记录一下其中的2操作数,在线操作
一点(i,j)在进行t次操作后对于(t,y)的贡献为C(t-i+y-j-1,t-i-1);
对于查询时我们就需要将当前的t+1进行查询,就可以就可以快速知道该点对于区间内的所有值的贡献
#include<bits/stdc++.h> using namespace std; const int maxn=4e6+500; const int mod=998244353; int pre[maxn+1],inv[maxn+1],len; struct ss { int x; int y; int w; }bos[maxn+1]; int quick(int a,int b) { int ans=1; while(b) { if(b&1)ans=1ll*ans*a%mod; a=1ll*a*a%mod; b>>=1; } return ans; } int C(int n,int m) { return 1ll*pre[n]*inv[m]%mod*inv[n-m]%mod; } int query(int pos,int t) { int ans=0; for(int i=1;i<=len;i++) { if(bos[i].y<=pos)ans=(ans+1ll*bos[i].w*C(pos-bos[i].y+t-bos[i].x-1,t-bos[i].x-1))%mod; } return ans; } void solve() { int n,m; scanf("%d%d",&n,&m); int t=0;len=0; while(m--) { int k; scanf("%d",&k); if(k==1) { int l,r,w; scanf("%d%d%d",&l,&r,&w); bos[++len]=(ss){t-1,l,w}; bos[++len]=(ss){t-1,r+1,(mod-w)%mod}; } else if(k==2)t++; else { int l,r; scanf("%d%d",&l,&r); printf("%d\n",(query(r,t+1)-query(l-1,t+1)+mod)%mod); } } } int main() { pre[0]=1; //int N=1e5; for(int i=1;i<=maxn;i++) { pre[i]=1ll*pre[i-1]*i%mod; } // cout<<pre[N]<<endl; inv[maxn]=quick(pre[maxn],mod-2); //cout<<inv[N]<<endl; for(int i=maxn-1;i>=0;i--) { inv[i]=1ll*inv[i+1]*(i+1)%mod; } int t; for(scanf("%d",&t);t;t--) { solve(); } return 0; }