一、题目
二、解法
这道题正向走不通,要反向做,设
d
p
[
i
]
dp[i]
dp[i]为
i
i
i到终点的概率:
f
i
=
f
i
−
1
×
(
1
−
p
i
)
+
f
i
+
1
×
p
i
f_i=f_{i-1}\times(1-p_i)+f_{i+1}\times p_i
fi=fi−1×(1−pi)+fi+1×pi
f
i
−
f
i
−
1
=
p
i
(
f
i
+
1
−
f
i
)
f_i-f_{i-1}=p_i(f_{i+1}-f_i)
fi−fi−1=pi(fi+1−fi)设
g
i
=
f
i
−
f
i
−
1
g_i=f_i-f_{i-1}
gi=fi−fi−1,那么:
g
i
=
p
i
(
g
i
+
1
+
g
i
)
g_i=p_i(g_{i+1}+g_i)
gi=pi(gi+1+gi),就可以得到:
g
i
+
1
=
1
−
p
i
p
i
g
i
g_{i+1}=\frac{1-p_i}{p_i}g_i
gi+1=pi1−pigi因为
f
n
=
1
,
f
0
=
0
f_n=1,f_0=0
fn=1,f0=0,所以
∑
i
=
1
n
g
i
=
1
\sum_{i=1}^ng_i=1
∑i=1ngi=1,设
t
i
=
1
−
p
i
p
i
t_i=\frac{1-p_i}{p_i}
ti=pi1−pi.,上面是用
[
1
,
n
]
[1,n]
[1,n]来推的,这里需要是
[
l
,
r
+
1
]
[l,r+1]
[l,r+1]:
g
l
(
1
+
t
l
+
t
l
t
l
+
1
.
.
.
.
.
+
t
l
.
.
t
r
)
=
1
g_l(1+t_l+t_lt_{l+1}.....+t_l..t_r)=1
gl(1+tl+tltl+1.....+tl..tr)=1那么我们维护下这个系数,就可以直接算答案了。
2020-06-18: 以前做过这题的,但是考同样的题没做出来,主要是定义问题,自闭了。
#include <cstdio>
#define db double
const int M = 400005;
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m;db p[M],x[M],y[M];
void up(int i)
{
x[i]=x[i<<1]*x[i<<1|1];
y[i]=y[i<<1]+y[i<<1|1]*x[i<<1];
}
void ins(int i,int l,int r,int id)
{
if(l==r)
{
x[i]=y[i]=p[id];
return ;
}
int mid=(l+r)>>1;
if(mid>=id) ins(i<<1,l,mid,id);
else ins(i<<1|1,mid+1,r,id);
up(i);
}
db ask1(int i,int l,int r,int L,int R)
{
if(l>R || L>r) return 1;
if(L<=l && r<=R) return x[i];
int mid=(l+r)>>1;
return ask1(i<<1,l,mid,L,R)*ask1(i<<1|1,mid+1,r,L,R);
}
db ask2(int i,int l,int r,int L,int R)
{
if(l>R || L>r) return 0;
if(L<=l && r<=R) return y[i];
int mid=(l+r)>>1;db ret=0;
ret=ask2(i<<1,l,mid,L,R);
if(mid<R) ret+=ask1(i<<1,l,mid,L,R)*ask2(i<<1|1,mid+1,r,L,R);
return ret;
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
{
int u=read(),v=read();
p[i]=1.0*(v-u)/u;
ins(1,1,n,i);
}
while(m--)
{
int op=read();
if(op==1)
{
int i=read(),u=read(),v=read();
p[i]=1.0*(v-u)/u;
ins(1,1,n,i);
}
if(op==2)
{
int l=read(),r=read();
printf("%.5lf\n",1.0/(ask2(1,1,n,l,r)+1.0));
}
}
}