不注意な
シーケンス、あなたが特定のポイントにあるとき、右へ行く可能性がある与えられた\(P_I \)は(左から(1-P_I \)\)、
与え\(M \)の操作を、操作があります二つのカテゴリ:
1点のXYZ:\(p_x \)修飾の値(\ \ FRAC Y} {} {Z \)
2 LR:からあなたを確認して下さい\(Lの\)を通過することなく、ランダムウォークを開始\(L-1 )\下部ケースに到達\(R + 1 \)確率
考え
我々は2つの値の範囲に設けられ\(バル、ValR \) 、
それぞれ、その右側エンドポイントから当選確率で始まるこのセクションの左端から開始点を獲得する確率を表します。
私たちが求めているということは、任意の間隔である\(バル\) 。
範囲を検討\(ヴァル\)を、2つのサブ間隔から来て転送する方法。
最初のため\(バル\)
必要があります\(S1.ValL \タイムズS2.ValL \)を表す\(SL \)左出発地と到着点を\(S2 \)は、次に、ポイントを左(R + 1 \ \)が、明らかに不足しているだろう(\、S2 \)S1の繰り返しクロスジャンプまでの期間。
我々は時間にそれが横方向のホップを計算するかもしれない列挙
\ [\ sum_ {i = 0
} ^ {\ inftyの} S1.ValRは^ iは時間(1-S2.ValLが)^ iは\ \] のように簡略化\ [\ FRAC {1} {1-S1.ValR
\時間(1-S2.ValL)} \] すなわち\ [バル= \ FRAC {S1.ValL \回S2.ValL} {1-S1.ValR \時間(1- S2.ValL)} \]
同様に、のために\(ValR \) 、そこクロスジャンプの場合であるが、右のギャップがある水平ジャンプの数を残しました。
\ [(1- S2.ValR)\
回S2.ValL回\ \ sum_ {i = 0} ^ {\ inftyのS1.ValR} ^ {I + 1} \回(1-S2.ValL)^ iは\] 単純化である\ [\ FRAC {(1-
S2.ValR)\回S2.ValL回S1.ValR \} {1-S1.ValR \時間(1-S2.ValL)} \] 一方、\(ValR \ )また、クロスジャンプせず、すなわち\(S2.ValR \) 。
総合ルック
\ [ValR = S2.ValR + FRAC \ {(1-S2.ValR)\回S2.ValL回S1.ValR \} {1- S1.ValR \時間(1-S2.ValL) } \]
バルとValRためには、ツリーラインのメンテナンスを使用することができます。
コード
オーバーロード、暴力的な合併を果たしていませんでした
#include<cstdio>
#include<algorithm>
using namespace std;
#define fi first
#define se second
const double ONE=1.0;
const int MAXN=100005;
const int INF=0X3F3F3F3F;
int N,Q;
double P[MAXN];
struct Node{
int l,r;pair<double,double>val;
}s[MAXN*8];
void Push_Up(int rt){
pair<double,double>ret1=s[rt*2].val,ret2=s[rt*2+1].val;
s[rt].val.fi=ret1.fi*ret2.fi/(1-ret1.se*(1-ret2.fi));
s[rt].val.se=ret2.se+(1-ret2.se)*ret2.fi*ret1.se/(1-ret1.se*(1-ret2.fi));
}
void Build(int rt,int l,int r){
s[rt].l=l;s[rt].r=r;
s[rt].val.fi=s[rt].val.se=-INF;
if(l==r){
s[rt].val.fi=P[l];
s[rt].val.se=P[l];
return ;
}
int mid=(l+r)/2;
Build(rt*2,l,mid);
Build(rt*2+1,mid+1,r);
Push_Up(rt);
}
void Insert(int rt,int p,double val){
if(s[rt].l>p||s[rt].r<p)return ;
if(s[rt].l==s[rt].r){s[rt].val.fi=s[rt].val.se=val;return ;}
Insert(rt*2,p,val);Insert(rt*2+1,p,val);Push_Up(rt);
}
pair<double,double>Query(int rt,int l,int r){
pair<double,double>ret;ret.fi=ret.se=-INF;
if(s[rt].l>r||s[rt].r<l)return ret;
if(s[rt].l>=l&&s[rt].r<=r)return s[rt].val;
pair<double,double>ret1,ret2;
ret1=Query(rt*2,l,r);
ret2=Query(rt*2+1,l,r);
if(ret1.fi==-INF&&ret2.fi==-INF)return ret;
if(ret1.fi==-INF)ret=ret2;
else if(ret2.fi==-INF)ret=ret1;
else{
ret.fi=ret1.fi*ret2.fi/(1-ret1.se*(1-ret2.fi));
ret.se=ret2.se+(1-ret2.se)*ret2.fi*ret1.se/(1-ret1.se*(1-ret2.fi));
}
return ret;
}
int main(){
scanf("%d%d",&N,&Q);
for(int i=1,A,B;i<=N;i++){
scanf("%d%d",&A,&B);
P[i]=ONE*A/B;
}
Build(1,1,N);
for(int i=1,k,x,y,z;i<=Q;i++){
scanf("%d%d%d",&k,&x,&y);
if(k==1){
scanf("%d",&z);
Insert(1,x,ONE*y/z);
}
if(k==2)printf("%.10f\n",Query(1,x,y).fi);
}
return 0;
}