「若是你對樹狀數組比較熟悉,不難發現可憐求的是後綴和」ios
設數列爲\(A\),那麼可憐求的就是\(A_{l-1}\)到\(A_{r-1}\)的和(即\(l-1\)的後綴減\(r\)的後綴,\(\sum_{i=l-1}^{r-1}A_i\)),而答案爲\(A_l\)到\(A_r\)的和(即\(\sum_{i=l}^{r}A_i\))這兩種答案都包含\(A_l\)到\(A_{r-1}\)的和,所以只需判斷\(A_{l-1}\)與\(A_r\)相等的機率就好了算法
那麼怎麼算?數組
考慮記下每次修改的影響,假設已知左端點\(a\)和右端點\(b\),那麼對於某一次修改區間\(l\)~\(r\),則只有當\(a\in[l,r]\)或\(b\in[l,r]\)時纔有影響,設\(p\)爲任選區間內一個數的機率,這裏分三種狀況討論:spa
那麼只要把全部的影響都合併起來就好了,設當前相同機率爲\(p\),當前修改不影響的機率\(q\),則相同機率更新爲\(p*q+(1-p)*(1-q)\)code
可是直接樸素必然TLE,所以咱們要尋找更高效的算法ip
考慮二維線段樹,設點\((x,y)\)表示\(A_x\)與\(A_y\)相等的機率,那麼咱們會驚奇的發現:string
每讀入一個修改,就用上面所說的影響更新區間,即\([1,l-1,l,r],[l,r,l,r],[l,r,r+1,n]\)三個區間,用上述式子合併區間it
詢問即查詢點\((l-1,r)\)的值io
\(l=1\)時,可憐求的是\(r\)的後綴和,所以咱們須要求\(r\)的後綴和與前綴和相等的機率class
這也能夠用相似方法,第一維咱們新增一個元素\(0\),用\([0,x]\)表示\(x\)的後綴和與前綴和相等的機率,那麼當修改區間\([l,r]\)時,區間\([1,l-1]\),\([r+1,n]\)中元素的後綴和與前綴和必定會被影響,即不被影響機率爲\(0\);而區間\([l,r]\)中元素有\(p\)的機率不被影響(即正好選到它,\(p\)的意義即爲上述),這時咱們也要更新。這樣當\(l=1\)時,直接查詢點\((l-1,r)\)的值便可
(代碼醜不要怪我)
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<string> #include<iostream> #include<queue> #include<iomanip> #include<algorithm> using namespace std; const int N=100010; const int MOD=998244353; int rt[N*21],n,cnt; struct tree { int l,r; int v;//卡空間,開int }tr[N*402]; inline long long mul(long long p,long long q)//p*q+(1-p)*(1-q) { long long res=p*q%MOD; res=(res+(1-p+MOD)*(1-q+MOD)%MOD)%MOD; return res; } inline long long power(long long x,long long y)//快速冪 { long long ans=1; while(y) { if(y&1) ans=ans*x%MOD; x=x*x%MOD,y>>=1; } return ans; } inline void updatay(int l,int r,int &id,int ly,int ry,long long p)//修改區間二維 { if(id==0) { cnt++; id=cnt; tr[id].v=1;//初始時都是0,所以相等機率爲1 } if(l>=ly&&r<=ry) { tr[id].v=mul(p,tr[id].v); return; } int mid=l+r>>1; if(ly<=mid) updatay(l,mid,tr[id].l,ly,ry,p); if(ry>mid) updatay(mid+1,r,tr[id].r,ly,ry,p); } inline void updatax(int l,int r,int id,int lx,int rx,int ly,int ry,long long p)//修改區間一維 { if(l>=lx&&r<=rx) { updatay(1,n,rt[id],ly,ry,p); return; } int mid=l+r>>1; if(lx<=mid) updatax(l,mid,id<<1,lx,rx,ly,ry,p); if(rx>mid) updatax(mid+1,r,id<<1|1,lx,rx,ly,ry,p); } long long quey(int l,int r,int id,int y)//查詢二維 { if(id==0) return 1;//初始時都是0,所以相等機率爲1 if(l==r) return tr[id].v; int mid=l+r>>1; long long res; if(y<=mid) res=mul(tr[id].v,quey(l,mid,tr[id].l,y)); else res=mul(tr[id].v,quey(mid+1,r,tr[id].r,y)); //合併沿途全部區間影響值 return res; } long long quex(int l,int r,int id,int x,int y)//查詢一維 { if(l==r) return quey(1,n,rt[id],y); int mid=l+r>>1; if(x<=mid) return mul(quey(1,n,rt[id],y),quex(l,mid,id<<1,x,y)); else return mul(quey(1,n,rt[id],y),quex(mid+1,r,id<<1|1,x,y)); //合併沿途全部區間影響值 } int main() { int i,j,k,q,op,l,r; long long p; scanf("%d%d",&n,&q); cnt=0; while(q--) { scanf("%d%d%d",&op,&l,&r); if(op==1) { p=power(r-l+1,MOD-2);//求逆元,即選某一個元素的機率 if(l>1) updatax(0,n,1,1,l-1,l,r,(1-p+MOD)%MOD),updatax(0,n,1,0,0,1,l-1,0); if(r<n) updatax(0,n,1,l,r,r+1,n,(1-p+MOD)%MOD),updatax(0,n,1,0,0,r+1,n,0); updatax(0,n,1,l,r,l,r,(1-p*2%MOD+MOD)%MOD),updatax(0,n,1,0,0,l,r,p); } else printf("%lld\n",quex(0,n,1,l-1,r)); } return 0; }