洛谷传送门
LOJ传送门
解析:
我们改变一下修改和回答方式。
令每个修改操作的被执行概率是 1 2 \frac{1}{2} 21,然后我们直接询问这棵线段树中被染黑的点数的期望,乘上 2 t 2^t 2t就行了, t t t是修改操作的次数。
设 f u , 0 f_{u,0} fu,0表示 u u u点被染黑的概率, f u , 1 f_{u,1} fu,1表示 u u u没黑但是 u u u存在某一个祖先黑了的概率, f u , 2 f_{u,2} fu,2表示 u u u没黑且不存在任何一个祖先黑了的概率。
显然初始化为 f u , 2 = 1 f_{u,2}=1 fu,2=1。
每次修改中,考虑 5 5 5类点:
1.访问但不定位
2.访问且定位
3.在
2
2
2类点的子树中
4.父亲为
1
1
1类点
5.这次修改管它屁事的点。
显然 5 5 5类点的所有概率没有任何变动。考虑前四种的变化:
1,访问但不定位 ( f 0 f 1 f 2 ) ⟹ ( 1 2 f 0 1 2 f 1 1 2 f 0 + 1 2 f 1 + f 2 ) \begin{pmatrix}f_0\\f_1\\f_2\end{pmatrix}\Longrightarrow\begin{pmatrix}\frac{1}2f_0\\\frac{1}{2}f_1\\\frac{1}{2}f_0+\frac{1}{2}f_1+f_2\end{pmatrix} ⎝⎛f0f1f2⎠⎞⟹⎝⎛21f021f121f0+21f1+f2⎠⎞
2,访问且被定位
(
f
0
f
1
f
2
)
⟹
(
f
0
+
1
2
f
1
+
1
2
f
2
1
2
f
1
1
2
f
2
)
\begin{pmatrix}f_0\\f_1\\f_2\end{pmatrix}\Longrightarrow\begin{pmatrix}f_0+\frac{1}2f_1+\frac{1}2f_2\\\frac{1}2f_1\\\frac{1}2f_2\end{pmatrix}
⎝⎛f0f1f2⎠⎞⟹⎝⎛f0+21f1+21f221f121f2⎠⎞
3,在 2 2 2类点的子树中
( f 0 f 1 f 2 ) ⟹ ( f 0 f 1 + 1 2 f 2 1 2 f 2 ) \begin{pmatrix}f_0\\f_1\\f_2\end{pmatrix}\Longrightarrow\begin{pmatrix}f_0\\f_1+\frac{1}{2}f_2\\\frac{1}{2}f_2\end{pmatrix} ⎝⎛f0f1f2⎠⎞⟹⎝⎛f0f1+21f221f2⎠⎞
特别的,我们需要为这类点维护懒标记,来计算它被多少次算在了 2 2 2的子树中。
4,父亲为
1
1
1类点
(
f
0
f
1
f
2
)
⟹
(
f
0
+
1
2
f
1
1
2
f
1
f
2
)
\begin{pmatrix}f_0\\f_1\\f_2\end{pmatrix}\Longrightarrow\begin{pmatrix}f_0+\frac{1}2f_1\\\frac{1}2f_1\\f_2\end{pmatrix}
⎝⎛f0f1f2⎠⎞⟹⎝⎛f0+21f121f1f2⎠⎞
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
using std::cout;
using std::cerr;
cs int mod=998244353,inv2=(mod+1)/2;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline void Inc(int &a,int b){(a+=b)>=mod?a-=mod:a;}
inline int dec(int a,int b){return a<b?a-b+mod:a-b;}
inline int mul(int a,int b){return (ll)a*b>=mod?(ll)a*b%mod:(ll)(a*b);}
inline int half(int a){return (a&1)?(a+mod)>>1:(a>>1);}
cs int N=1e5+5;
int i2[N];
inline void init(int lim){
i2[0]=1;
for(int re i=1;i<=lim;++i)i2[i]=mul(inv2,i2[i-1]);
}
struct vec{
int a[3];
vec(){}
int &operator[](int offset){return a[offset];}
cs int &operator[](int offset)cs{return a[offset];}
void push1(){
a[0]=half(a[0]);
a[1]=half(a[1]);
Inc(a[2],add(a[0],a[1]));
}
void push2(){
a[1]=half(a[1]);
a[2]=half(a[2]);
Inc(a[0],add(a[1],a[2]));
}
void push3(int p){
int tmp=mul(i2[p],a[2]);
Inc(a[1],dec(a[2],tmp));
a[2]=tmp;
}
void push4(){
Inc(a[0],half(a[1]));
a[1]=half(a[1]);
}
};
vec mat[N<<2];
int tag[N<<2],sum[N<<2];
cs int lim=N<<2;
inline void pushup(int k){
sum[k]=mat[k][0];
if((k<<1)<lim)Inc(sum[k],add(sum[k<<1],sum[k<<1|1]));
}
inline void build(int k,int l,int r){
mat[k][2]=1;
if(l==r)return ;
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
inline void push3(int k,int p){
tag[k]+=p;
mat[k].push3(p);
pushup(k);
}
inline void push4(int k){
mat[k].push4();
pushup(k);
}
inline void pushdown(int k){
if(tag[k]){
if((k<<1)<lim)
push3(k<<1,tag[k]),push3(k<<1|1,tag[k]);
tag[k]=0;
}
}
inline void modify(int k,int l,int r,cs int &ql,cs int &qr){
pushdown(k);
if(ql<=l&&r<=qr){
mat[k].push2();
if(l^r){
push3(k<<1,1);
push3(k<<1|1,1);
}
pushup(k);
return ;
}
int mid=(l+r)>>1;
mat[k].push1();
if(qr<=mid){
push4(k<<1|1);
modify(k<<1,l,mid,ql,qr);
}
else if(mid<ql){
push4(k<<1);
modify(k<<1|1,mid+1,r,ql,qr);
}
else {
modify(k<<1,l,mid,ql,qr);
modify(k<<1|1,mid+1,r,ql,qr);
}
pushup(k);
}
int n,m;
signed main(){
n=getint(),m=getint();
init(m);
build(1,1,n);
int now=1;
while(m--)switch(getint()){
case 1:{
int l=getint(),r=getint();
modify(1,1,n,l,r);
Inc(now,now);
break;
}
case 2:{
cout<<mul(now,sum[1])<<"\n";
break;
}
}
return 0;
}