以后写题前还是要冷静分析清楚再动手啊.....
$ Think twice,code once$
传送门:here
大致题意:
有一个写挂的树状数组,$ query$的是后缀和,$ query(0)$时返回$ 0$
有$ m$次操作,
$ 1 L R$表示在$ L...R$中等概率选取一个点$ update$
$ 2 L R$表示求$ query(L,R)$和正确的树状数组$ query$在模$ 2$意义下相同的概率
先特判掉询问时$ L==1$的情况
发现相当于询问$ [L-1..n]-[R..n]-[1..R]+[1..L-1]=val[L-1]-val[R]$模$ 2$意义下的值
这题询问的两个端点$ L,R$不能独立考虑,因为一次$ update$只能选取一个点进行更新
考虑暴力
我们枚举一次$ query$前的所有$ update(L,R)$
如果$ query$的$ L-1$和$ R$均在$ update$区间内,则有$ frac{2}{len}$的概率改变模$ 2$意义下的结果
否则若只有一个端点在$ update$区间内,则有$ frac{1}{len}$的概率改变模$ 2$意义下的结果
我们用$ p1,p2$分别表示这次更新和更新前结果为$ 0$的概率,则有$ merge(p1,p2)=p1p2+(1-p1)(1-p2)$
可以令$ p1=1$然后每次求出$ p2$并进行合并
考虑用树套树维护这个东西
对于每一次查询$ L,R$相当于查询坐标$ (L-1,R)$上的结果
对于每一个$ change(1,L,R)$,我们给矩形内打上$ frac{2}{len}$概率修改的标记,矩形外只包含$ L-1$或只包含$ R$的四块矩形打上$ frac{2}{len}$概率修改的标记
由于查询的$(L-1,R)$保证$ L-1<R$,因此只包含$ L-1$或只包含$ R$的四块矩形里我们只需要修改两块以节省空间
由于单点查询可以轻松用标记永久化维护
洛谷上第$ 13$个点只有修改没有询问,可能需要卡一波空间
记得特判$ L=1$
$ my code:$
#include<ctime> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #define p 998244353 #define rt register int #define ll long long using namespace std; inline ll read(){ ll x = 0; char zf = 1; char ch = getchar(); while (ch != '-' && !isdigit(ch)) ch = getchar(); if (ch == '-') zf = -1, ch = getchar(); while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * zf; } void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);} void writeln(const ll y){write(y);putchar(' ');} int i,j,k,m,n,x,y,z,cnt,Cnt; ll inv[100010]; struct segment{ int ls,rs,val; }a[36000010]; int to[400010]; int Root,ans; inline void merge(int &x,int y){ x=(1ll*x*y+(1ll-x)*(1-y))%p; } void Insert(int &x,int L,int R,int L1,int R1,int gl){ if(L>R1||R<L1)return; if(!x)x=++cnt,a[x].val=1; if(L>=L1&&R<=R1)return merge(a[x].val,gl); const int mid=L+R>>1; Insert(a[x].ls,L,mid,L1,R1,gl); Insert(a[x].rs,mid+1,R,L1,R1,gl); } void insert(int &x,int L,int R,int L1,int R1,int L2,int R2,int gl){ if(L>R1||R<L1)return;if(!x)x=++Cnt; if(L>=L1&&R<=R1)return Insert(to[x],1,n,L2,R2,gl); const int mid=L+R>>1; insert(a[x].ls,L,mid,L1,R1,L2,R2,gl); insert(a[x].rs,mid+1,R,L1,R1,L2,R2,gl); } void Query(int x,int L,int R,int w){ if(!x)return;merge(ans,a[x].val); const int mid=L+R>>1; if(w<=mid)Query(a[x].ls,L,mid,w); else Query(a[x].rs,mid+1,R,w); } void query(int x,int L,int R,int w1,int w2){ if(!x)return; Query(to[x],1,n,w2); const int mid=L+R>>1; if(w1<=mid)query(a[x].ls,L,mid,w1,w2); else query(a[x].rs,mid+1,R,w1,w2); } int main(){ n=read();m=read();int t=0; inv[1]=1; for(rt i=2;i<=n;i++)inv[i]=inv[p%i]*(p-p/i)%p; cnt=400000; for(rt i=1;i<=m;i++){ x=read();int L=read(),R=read(); if(x==1){ int len=R-L+1,v=1;t++; insert(Root,0,n,L,R,L,R,1-2*inv[len]); insert(Root,0,n,L,R,R+1,n,1-inv[len]); insert(Root,0,n,0,L-1,L,R,1-inv[len]); } else{ z=i;ans=1;query(Root,0,n,L-1,R); if(L==1&&(t&1))ans=(1-ans)%p; (ans+=p)%=p; writeln(ans); } } return 0; }