早上在知乎看到吉司机说这是一道期望+数据结构
一脸懵逼
原来就是把计数看成期望乘上情况
分析一波复制操作
就可以发现其实就是求每次操作有
/
/
/没有的
2
t
2^t
2t种情况的
t
a
g
tag
tag之和
如果按照线段树这个样子
似乎……可以直接用线段树维护?
维护一个
t
r
[
u
]
tr[u]
tr[u]表示线段树上点
u
u
u当前有多少种情况为
1
1
1
没有影响到的点显然 t a g tag tag是不会改变的的,也就是 t r tr tr乘2
对于所有线段树遍历而且非修改的点,他们的
t
a
g
tag
tag显然都被变成
0
0
0了
所以这些点
t
r
tr
tr不变
对于所有直接修改到的节点显然无论前面情况怎么样现在的
t
a
g
tag
tag都为1
也就是加上
2
t
2^t
2t
发现
p
u
s
h
d
o
w
n
pushdown
pushdown还会影响所有修改节点的兄弟
但是只有当原来父亲以上有
t
a
g
tag
tag为1的时候这里才会变成1
再维护一个
f
[
u
]
f[u]
f[u]表示有多少种情况
f
[
u
]
f[u]
f[u]到根会有点
t
a
g
tag
tag为1
t
r
tr
tr直接加上
f
f
f就是了
那考虑
f
f
f怎么维护
对于不被修改的点,
t
a
g
tag
tag不变,
f
f
f乘2
修改路径上的点, t a g tag tag变成了0, f f f不变
被修改的点, t a g tag tag变成了 1 1 1, f f f加上 2 t 2^t 2t
所有兄弟, t a g tag tag变成了 1 1 1, f f f乘2
又发现所有不被修改的点都是兄弟的儿子
所以就只用讨论3种情况了
修改路径上的点: t r tr tr不变, f f f不变
被修改的点: t r + = 2 t tr+=2^t tr+=2t,子树所有 f + = 2 t f+=2^t f+=2t
兄弟节点:子树所有 t r + = f tr+=f tr+=f,子树所有 f = f ∗ 2 f=f*2 f=f∗2
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
const int N=100005;
const int mod=998244353;
inline int add(int a,int b){
return a+b>=mod?a+b-mod:a+b;
}
inline int mul(int a,int b){
return 1ll*a*b>=mod?1ll*a*b%mod:a*b;
}
inline void dec(int &a,int b){
a=a>=b?a-b:a-b+mod;
}
inline void selfadd(int &a,int b){
a=add(a,b);
}
inline void selfmul(int &a,int b){
a=mul(a,b);
}
int ans,t,n,m,res;
namespace Seg{
int tr[N<<2],f[N<<2],mulf[N<<2],addf[N<<2],mul[N<<2];
#define lc (u<<1)
#define rc ((u<<1)|1)
#define mid ((l+r)>>1)
inline void build(int u,int l,int r){
mulf[u]=mul[u]=1;
if(l==r)return;
build(lc,l,mid),build(rc,mid+1,r);
}
inline void pushmulf(int u,int k){
selfmul(addf[u],k),selfmul(f[u],k),selfmul(mulf[u],k);
}
inline void pushadd(int u,int k){
selfadd(f[u],k),selfadd(addf[u],k);
}
inline void pushmul(int u,int k){
selfmul(mul[u],k),selfmul(tr[u],k);
}
inline void pushdown(int u){
if(mulf[u])pushmulf(lc,mulf[u]),pushmulf(rc,mulf[u]),mulf[u]=1;
if(addf[u])pushadd(lc,addf[u]),pushadd(rc,addf[u]),addf[u]=0;
if(mul[u])pushmul(lc,mul[u]),pushmul(rc,mul[u]),mul[u]=1;
}
void update(int u,int l,int r,int st,int des){
if(st<=l&&r<=des){
dec(ans,tr[u]);
selfadd(tr[u],t),pushadd(u,t),selfmul(mul[u],2);
selfadd(res,tr[u]);
return;
}
if(r<st||des<l){
dec(ans,tr[u]);
selfadd(tr[u],f[u]),selfmul(mul[u],2),pushmulf(u,2);
selfadd(res,tr[u]);
return;
}
pushdown(u);
dec(ans,tr[u]),selfadd(res,tr[u]);
update(lc,l,mid,st,des);
update(rc,mid+1,r,st,des);
}
}
using namespace Seg;
int main(){
n=read(),m=read();
build(1,1,n);t=1;
for(int i=1;i<=m;i++){
int op=read();
if(op==1){
int l=read(),r=read();
res=0;
update(1,1,n,l,r);
selfmul(t,2);
selfmul(ans,2);
selfadd(ans,res);
}
else cout<<ans<<'\n';
}
}