题目
思路
注意题目中最后需要达到\(r+1\)号赌场
设到\(i\)不走出$r+1 \(的概率为\)f_i$
为了简便,我们定义\(p_i=\frac{x_i}{y_i}\)
根据题意,有一个显然的方程
\(f_i=f_{i+1}p_i+f_{i-1}*(1-p_i)\)
\(f_i=f_{i+1}p_i+f_{i-1}-f_{i-1}*p_i\)
\(f_i-f_{i-1}=p_i(f_{i+1}-f_{i-1})\)
定义\(g_i=f_i-f_{i-1}\)
\(g_i=p_i(g_{i+1}+g_{i})\)
\(g_i(1-p_i)=p_ig_{i+1}\)
\(g_{i+1}=\frac{(1-p_i)}{p_i}g_i\)
根据\(f\)的定义,显然有\(f_{r+1}=1,f_{l-1}=0\)
\(\begin{aligned}1&=f_{r+1}-f_{l-1}\\&=\sum_{i=l}^{r+1}g_i\\&=g_l*\sum_{i=l}^{r+1}\prod_{j=l}^{i-1}\frac{1-p_j}{p_j}\end{aligned}\)
这里进行一点特殊说明,如果i-1<l则累加上去为的值1
然后就可以算出\(g_l\)的值
之后?
\(g_{l}=f_l-f_{l-1}=f_l\)
现在主要考虑如何后面快速后面那一团乘积
可以考虑用差分的方式
定义\(t_i=\frac{1-p_i}{p_i}\)
首先我们将\(1\)分离出来
原式即为\(1+\sum_{i=l}^{r}\prod_{j=l}^{i}t_j\)
明显有
\((\prod_{i=1}^{l-1}t_i)*\sum_{i=l}^{r}\prod_{j=l}^{i}t_j=\sum_{i=1}^{r}\prod_{j=1}^{i}t_j-\sum_{i=1}^{l-1}\prod_{j=1}^{i}t_j\)
\(\sum_{i=l}^{r}\prod_{j=l}^{i}t_j=\frac{\sum_{i=1}^{r}\prod_{j=1}^{i}t_j-\sum_{i=1}^{l-1}\prod_{j=1}^{i}t_j}{\prod_{i=1}^{l-1}t_i}\)
此时我们只需要用线段树组分别维护\(\sum_{i=1}^{x}\prod_{j=1}^{i}t_j\)和\(\prod_{i=1}^{x}t_i\)
代码
#include<iostream>
using namespace std;
int n,m;
int opt;
int a,b,c;
double p[100005];
struct node
{
int l;
int r;
double w1;
double w2;
}tre[400005];
void build(int l,int r,int k)
{
tre[k].l=l;
tre[k].r=r;
if(l==r)
{
tre[k].w1=tre[k].w2=p[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
tre[k].w1=tre[k<<1].w1*tre[k<<1|1].w1;
tre[k].w2=tre[k<<1].w2+tre[k<<1].w1*tre[k<<1|1].w2;
}
void change(int u,int k,double a)
{
if(tre[k].l>u||tre[k].r<u)
return;
if(tre[k].l==tre[k].r)
{
tre[k].w1=tre[k].w2=a;
return;
}
change(u,k<<1,a);
change(u,k<<1|1,a);
tre[k].w1=tre[k<<1].w1*tre[k<<1|1].w1;
tre[k].w2=tre[k<<1].w2+tre[k<<1].w1*tre[k<<1|1].w2;
}
double ask1(int l,int r,int k)
{
if(l>tre[k].r||tre[k].l>r)
return 1;
if(l<=tre[k].l&&tre[k].r<=r)
return tre[k].w1;
double ret=1;
ret=ret*ask1(l,r,k<<1);
ret=ret*ask1(l,r,k<<1|1);
return ret;
}
double ask2(int l,int r,int k)
{
if(l>tre[k].r||tre[k].l>r)
return 0;
if(l<=tre[k].l&&tre[k].r<=r)
return tre[k].w2;
double ret=0;
ret+=ask2(l,r,k<<1);
if(r>((tre[k].l+tre[k].r)>>1))
ret+=ask2(l,r,k<<1|1)*ask1(l,(tre[k].l+tre[k].r)>>1,k<<1);
return ret;
}
void debug(int k)
{
cout<<tre[k].w1<<' '<<tre[k].w2<<'\n';
if(tre[k].l==tre[k].r)
{
cout<<"f\n";
return;
}
debug(k<<1);
debug(k<<1|1);
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int a,b;
cin>>a>>b;
p[i]=1.0*(b-a)/a;
//cout<<p[i]<<' ';
}
//cout<<'\n';
build(1,n,1);
//debug(1);
for(int i=1;i<=m;i++)
{
cin>>opt;
if(opt==1)
{
cin>>a>>b>>c;
p[a]=1.0*(c-b)/b;
change(a,1,p[a]);
}
else
{
cin>>a>>b;
printf("%.5lf\n",1/(ask2(a,b,1)+1));
}
//debug(1);
/*for(int j=1;j<=n;j++)
cout<<p[j]<<' ';
cout<<'\n';*/
}
return 0;
}