刚开始看到这道题的时候想的是线段树分治,毕竟这里的乘法和加法都是可以撤销的.
但是后来发现如果想要线段树分治的话就必须要满足交换律,但是标记 $(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
",(ll)((ll)s[x].val*c.x%mod+c.y)%mod);
}
}
return 0;
}