传送门
每次等价于一部分操作一部分不操作。
显然一个点被标记只可能是被直接标记或者祖先被标记,于是我们对于每一个节点
维护它被标记的概率与祖先被标记的概率。
把每个区间分类讨论更新即可。
有如下几种情况:
1.覆盖祖先但未覆盖自己
2. 直接覆盖当前点
3. 经过当前点继续在子树中修改
4. 修改到父亲处向兄弟子树走
5. 修改到非父亲祖先向兄弟子树走
然后用线段树维护即可。
详见代码
代码:
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
static char buf[rlen],*ib,*ob;
(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
return ib==ob?-1:*ib++;
}
inline int read(){
int ans=0;
char ch=gc();
while(!isdigit(ch))ch=gc();
while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
return ans;
}
typedef long long ll;
const int mod=998244353,inv=(mod+1)/2,N=1e5+5;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline void Add(int&a,const int&b){a=a+b>=mod?a+b-mod:a+b;}
int n,m,det=1;
namespace sgt{
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
struct Node{int l,r,f,g,s,tf,tg;}T[N<<3];
inline void pushup(int p){T[p].s=add(add(T[lc].s,T[p].f),T[rc].s);}
inline void pf(int p,int v){T[p].f=mul(T[p].f,v),T[p].tf=mul(T[p].tf,v),T[p].s=mul(T[p].s,v);}
inline void pg(int p,int v){T[p].g=mul(T[p].g,v),T[p].tg=mul(T[p].tg,v);}
inline void pushdown(int p){
if(T[p].tf^1)pf(lc,T[p].tf),pf(rc,T[p].tf),T[p].tf=1;
if(T[p].tg^1)pg(lc,T[p].tg),pg(rc,T[p].tg),T[p].tg=1;
}
inline void build(int p,int l,int r){
T[p].l=l,T[p].r=r,T[p].tf=T[p].tg=T[p].g=1,T[p].f=T[p].s=0;
if(l==r)return;
build(lc,l,mid),build(rc,mid+1,r);
}
inline void modify(int p){
pushdown(p);
Add(T[p].f,dec(det,T[p].g)),T[p].g=add(T[p].g,T[p].g);
pf(lc,2),pg(lc,2),pf(rc,2),pg(rc,2),pushup(p);
}
inline void update(int p,int ql,int qr){
pushdown(p);
if(ql<=T[p].l&&T[p].r<=qr)return Add(T[p].f,det),pf(lc,2),pf(rc,2),pushup(p);
Add(T[p].g,det);
if(qr<=mid)return update(lc,ql,qr),modify(rc),pushup(p);
if(ql>mid)return update(rc,ql,qr),modify(lc),pushup(p);
update(lc,ql,qr),update(rc,ql,qr),pushup(p);
}
#undef lc
#undef rc
#undef mid
}
int main(){
n=read(),m=read();
sgt::build(1,1,n);
for(ri op,l,r;m;--m){
op=read();
switch(op){
case 1:{
l=read(),r=read();
sgt::update(1,l,r);
det=add(det,det);
break;
}
case 2:{
cout<<sgt::T[1].s<<'\n';
break;
}
}
}
return 0;
}