【LOJ#3043】【洛谷P5280】【ZJOI2019】—线段树(计数dp+线段树)
早上在知乎看到吉司机说这是一道期望+数据结构
一脸懵逼
原来就是把计数看成期望乘上情况
分析一波复制操作
就可以发现其实就是求每次操作有没有的种情况的之和
如果按照线段树这个样子
似乎……可以直接用线段树维护?
维护一个表示线段树上点当前有多少种情况为
没有影响到的点显然是不会改变的的,也就是乘2
对于所有线段树遍历而且非修改的点,他们的显然都被变成了
所以这些点不变
对于所有直接修改到的节点显然无论前面情况怎么样现在的都为1
也就是加上
发现还会影响所有修改节点的兄弟
但是只有当原来父亲以上有为1的时候这里才会变成1
再维护一个表示有多少种情况到根会有点为1
直接加上就是了
那考虑怎么维护
对于不被修改的点,不变,乘2
修改路径上的点,变成了0,不变
被修改的点,变成了,加上
所有兄弟,变成了,乘2
又发现所有不被修改的点都是兄弟的儿子
所以就只用讨论3种情况了
修改路径上的点:不变,不变
被修改的点:,子树所有
兄弟节点:子树所有,子树所有
#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';
}
}