題意
每次詢問一段區間[l,r],求從最左邊走到最右邊(r+1)的概率(若走到l-1,則GG了),每個點上寫有向右走的概率。支援單點修改。
思考
若只查詢一次,那隻要知道每個點在不走到l-1的情況下,向右移動一格的概率就行了,最後乘起來就是答案。
但我們忽略了一件事情,若從一個區間的某一點出發,從左邊走出去和右邊走出去的概率和為1(不可能停在中間),於是我們要設計一個狀態,並能夠合併,這樣才有可能優化複雜度。
設 [l,r] 區間的L為從第l個點(最左邊)出發,在右邊走出去的概率,R為第R個點出發,在左邊走出去的概率。
[L1 | --> | R1] | [L2 | --> | R2] |
---|---|---|---|---|---|
[ L | -- | -- | -- | --> | R ] |
請記住,他們每個的實際意義。因為每個點要麼從左邊走出去,要麼從右邊走出去,所(1-L1)的實際意義就是從(左邊出發,不從右邊走出),即(從左邊出發,從左邊走出去的概率)。
那麼若有兩個連續的區間,合併成一個新區間會有怎樣的答案? 設左右兩個區間的答案分別為L1,R1,L2,R2,則:
L = L1*L2 走到右邊還要再走到更右邊
+ L1(1-L2)(1-R1)*L2 第一次向右邊走失敗了,再退回來再向右走
+ L1(1-L2)(1-R1)(1-L2)(1-R1)*L2 反反覆覆.......
+.......
整理一下,
L = L1L2+L1L2(1-L2)(1-R1)+L1L2(1-L2)2+.......
(1-L2)(1-R1)L = L1L2(1-L2)(1-R1)+L1L2(1-L2)2+.......
作差,
L(1-(1-L2)(1-R1))=L1L2
L=L1L2/(1-(1-L2)(1-R1))
R也可以類似地得到,但注意它們的和不一定為1,因為是兩個不同的端點。
簡單地線段樹維護。
程式碼
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1E5+5; 4 int n,m; 5 double x,y,a[maxn]; 6 struct tree{int l,r;double L,R;}t[maxn*4]; 7 tree merge(tree x,tree y) 8 { 9 tree z; 10 z.l=x.l;z.r=y.r; 11 z.L=x.L*y.L/(1-(1-y.L)*(1-x.R)); 12 z.R=x.R*y.R/(1-(1-y.L)*(1-x.R));//不要認為反一反就對了QAQ 13 return z; 14 } 15 void build(int l,int r,int num) 16 { 17 t[num].l=l,t[num].r=r; 18 if(l==r) 19 { 20 t[num].L=a[l]; 21 t[num].R=1-a[l]; 22 return; 23 } 24 int mid=(l+r)>>1; 25 build(l,mid,num*2);build(mid+1,r,num*2+1); 26 t[num]=merge(t[num*2],t[num*2+1]); 27 } 28 void change(int pos,double val,int num) 29 { 30 if(t[num].l==t[num].r) 31 { 32 t[num].L=val; 33 t[num].R=1-val; 34 return; 35 } 36 int mid=(t[num].l+t[num].r)>>1; 37 if(pos<=mid)change(pos,val,num*2); 38 else change(pos,val,num*2+1); 39 t[num]=merge(t[num*2],t[num*2+1]); 40 } 41 tree ask(int L,int R,int num) 42 { 43 if(L<=t[num].l&&t[num].r<=R)return t[num]; 44 int mid=(t[num].l+t[num].r)>>1; 45 if(R<=mid)return ask(L,R,num*2); 46 else if(mid<L)return ask(L,R,num*2+1); 47 else return merge(ask(L,R,num*2),ask(L,R,num*2+1)); 48 } 49 int main() 50 { 51 ios::sync_with_stdio(false); 52 cin>>n>>m; 53 for(int i=1;i<=n;++i) 54 { 55 cin>>x>>y; 56 a[i]=x/y; 57 } 58 build(1,n,1); 59 while(m--) 60 { 61 int opt,d; 62 cin>>opt; 63 if(opt==1) 64 { 65 cin>>d>>x>>y; 66 change(d,x/y,1); 67 } 68 else 69 { 70 int l,r; 71 cin>>l>>r; 72 cout<<fixed<<setprecision(8)<<ask(l,r,1).L<<endl; 73 } 74 } 75 return 0; 76 }