刚开始看到这道题的时候想的是线段树分治,毕竟这里的乘法和加法都是可以撤销的.
但是后来发现如果想要线段树分治的话就必须要满足交换律,但是标记 $(x,y)$ ( 乘 $x$ 后加 $y$)只满足结合律,不满足交换律.
那么就考虑 kdtree.
kdtree 是维护平面上点的数据结构,然后我们可以把每个询问抽象成点 $(t_{i},x_{i})$ 表示时间轴和坐标轴.
那么每一次的修改就可以表示成平面上的一个矩阵了,只需在 kdtree 上维护一个标记就行.
在查询的时候我的做法是暴力跳父亲节点,单次复杂度是 $O($kdtree树高$)$.
code:
#include <bits/stdc++.h> #define N 160000 #define ll long long #define mod 998244353 #define lson s[now].ch[0] #define rson s[now].ch[1] #define setIO(s) freopen(s".in","r",stdin) using namespace std; int d,n,m; int last[N],L[N],R[N],cur[N],GE[N]; struct Tag { int x,y; Tag(int a=1,int b=0){ x=a,y=b; } Tag operator+(const Tag b) const { Tag c; c.x=(ll)x*b.x%mod; c.y=(ll)((ll)y*b.x%mod+b.y)%mod; return c; } void init(int a=1,int b=0) { x=a,y=b; } }ope[N]; struct data { Tag h; int ch[2],p[2],mi[2],ma[2],f,val,id; bool operator<(const data b) const { return p[d]==b.p[d]?p[d^1]<b.p[d^1]:p[d]<b.p[d]; } int isin(data b) { int fl=1; for(int i=0;i<2;++i) if(mi[i]<b.mi[i]||ma[i]>b.ma[i]) fl=0; return fl; } int isout(data b) { int fl=0; for(int i=0;i<2;++i) if(mi[i]>b.ma[i]||ma[i]<b.mi[i]) fl=1; return fl; } }s[N]; void pushup(int x,int y) { for(int i=0;i<2;++i) { s[x].mi[i]=min(s[x].mi[i],s[y].mi[i]); s[x].ma[i]=max(s[x].ma[i],s[y].ma[i]); } } int build(int l,int r,int o) { int mid=(l+r)>>1; d=o,nth_element(s+l,s+mid,s+1+r); for(int i=0;i<2;++i) s[mid].mi[i]=s[mid].ma[i]=s[mid].p[i]; s[mid].val=0; s[mid].h.init(); GE[s[mid].id]=mid; if(mid>l) { s[mid].ch[0]=build(l,mid-1,o^1); s[s[mid].ch[0]].f=mid; pushup(mid,s[mid].ch[0]); } if(r>mid) { s[mid].ch[1]=build(mid+1,r,o^1); s[s[mid].ch[1]].f=mid; pushup(mid,s[mid].ch[1]); } return mid; } void mark(int x,Tag v) { s[x].h=s[x].h+v; s[x].val=(ll)((ll)s[x].val*v.x%mod+v.y)%mod; } void pushdown(int now) { if(lson) mark(lson,s[now].h); if(rson) mark(rson,s[now].h); s[now].h.init(); } void update(int now,data p,Tag v) { if(s[now].isout(p)) return; if(s[now].isin(p)) { mark(now,v); return; } if(s[now].p[0]>=p.mi[0]&&s[now].p[0]<=p.ma[0]&&s[now].p[1]>=p.mi[1]&&s[now].p[1]<=p.ma[1]) s[now].val=(ll)((ll)s[now].val*v.x%mod+v.y)%mod; pushdown(now); if(lson) update(lson,p,v); if(rson) update(rson,p,v); } int main() { // setIO("input"); scanf("%d%d",&n,&m); int x,y,z,o,cnt=0; for(int i=1;i<=m;++i) { scanf("%d",&o); cur[i]=o; if(o<=2) { last[i]=m; scanf("%d%d%d",&L[i],&R[i],&z); if(o==1) ope[i].x=1,ope[i].y=z%mod; if(o==2) ope[i].x=z%mod,ope[i].y=0; } else { scanf("%d",&x); if(o==3) { ++cnt; s[cnt].p[0]=i; s[cnt].p[1]=x; s[cnt].id=i; } if(o==4) last[x]=i-1; } } data tmp; int root=build(1,cnt,0); for(int i=1;i<=m;++i) { if(cur[i]<=2) { tmp.mi[0]=i,tmp.ma[0]=last[i]; tmp.mi[1]=L[i],tmp.ma[1]=R[i]; update(root,tmp,ope[i]); } if(cur[i]==3) { x=GE[i]; Tag c(1,0); for(int j=s[x].f;j;j=s[j].f) c=c+s[j].h; printf("%d\n",(ll)((ll)s[x].val*c.x%mod+c.y)%mod); } } return 0; }