首先我们发现如果reverse下树状数组所操作的数组的话,它写的代码是完全正确的,但是reverse之后前缀变成了后缀,所以,它写了一个正确的单点修改求后缀和的数据结构
那么我们发现,对于一个通常的询问,其实是在询问(l-1,r)这两个点相同的概率
,然后一个错误的思路是用线段树维护每一个点被修改的概率,但是这样做是错的,因为对于一次操作,修改且只修改一个点,如果按照线段树来做,其实是会导致一次操作修改多个点的
那怎么办呢,二维线段树好了,因为它可以同时维护两维的信息
设二元组(x,y)的值表示位置为x的点和位置为y的点相同的概率
那么我们发现,对于一个操作(l,r),设这次操作的区间长度为len
他会对三种类型的二元组产生影响
1.左端点在(l,r)内且右端点不在(l,r)的二元组
2.右端点在(l,r)内且左端点不在(l,r)的二元组
3.左右端点同时在(l,r)内的二元组
对于第一种和第二种二元组,这次修改有1/len的概率取反它们,对于第3种二元组这次修改有2/len的概率取反它们(因为不存在同时落在x和y上的操作,每次操作之后修改一个点)
发现l==1的时候询问的是前缀和是否等于后缀和
单开一个线段树记录即可,注意特判
上代码~
// luogu-judger-enable-o2
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<cstdio>
#define ls ch[o][0]
#define rs ch[o][1]
#define mid (l+r>>1)
const int M=101000,mod=998244353;int n,m,l,r,opt;
int merge(int x,int y){return (1ll*x*y%mod+1ll*(1ll-x+mod)%mod*(1ll-y+mod)%mod)%mod;}
int pow(int a,int k){int ans=1;for(;k;a=1ll*a*a%mod,k>>=1) if(k&1) ans=1ll*ans*a%mod;return ans;}
struct SEG{int root[M<<8];
struct SEG2{
int ch[M<<8][2],tot,p[M<<8];
void modify(int &o,int l,int r,int ql,int qr,int P){
if(r<ql||l>qr) return ;if(!o) o=++tot,p[o]=1;
if(ql<=l&&r<=qr) {p[o]=merge(p[o],P);return ;}
modify(ls,l,mid,ql,qr,P);modify(rs,mid+1,r,ql,qr,P);
}
int query(int o,int l,int r,int ins){
if(!o)return 1; if(l==r) return p[o];
if(ins<=mid) return merge(p[o],query(ls,l,mid,ins));
else return merge(p[o],query(rs,mid+1,r,ins));
}
}T;
void modify(int o,int l,int r,int ql,int qr,int ql2,int qr2,int p){
if(r<ql||l>qr) return ;
if(ql<=l&&r<=qr) {T.modify(root[o],0,n,ql2,qr2,p);return ;}
modify(o<<1,l,mid,ql,qr,ql2,qr2,p);modify(o<<1|1,mid+1,r,ql,qr,ql2,qr2,p);
}
int query(int o,int l,int r,int ql,int qr){
if(l==r) return T.query(root[o],0,n,qr);
if(ql<=mid) return merge(T.query(root[o],0,n,qr),query(o<<1,l,mid,ql,qr));
else return merge(T.query(root[o],0,n,qr),query(o<<1|1,mid+1,r,ql,qr));
}
}T;
int main(){
scanf("%d%d",&n,&m);
while(m--){scanf("%d%d%d",&opt,&l,&r);
if(opt==1) {int P=pow(r-l+1,mod-2);
if(l>1) T.modify(1,0,n,1,l-1,l,r,(1-P+mod)%mod),T.modify(1,0,n,0,0,0,l-1,0);
if(r<n) T.modify(1,0,n,l,r,r+1,n,(1-P+mod)%mod),T.modify(1,0,n,0,0,r+1,n,0);
T.modify(1,0,n,l,r,l,r,(1-2*P%mod+mod)%mod);
T.modify(1,0,n,0,0,l,r,P);
}else printf("%d\n",T.query(1,0,n,l-1,r));
}
}