题目描述:
题解:
一眼线段树维护区间某值,然后就不会了……
肝到$O(nq)$就弃疗了,题解的方法比较奇妙。
我的$O(nq)$做法是$$f_i=k_{i-1}*f_{i-1}+(1-k_{i+1})*f_{i+1}$$,最后取$f_r$,是一个概率方程;
而题解是这样的:$$f_i=(1-k_{i})*f_{i-1}+k_{i}*f_{i+1}$$,最后取$f_l$,是一个期望方程……
这个期望方程可以变成:$$f_i-f_{i-1}=k_i*(f_{i+1}-f_{i-1})$$
然后设$g_i=f_i-f_{i-1}$,则上式可变成:$$g_i=k_i*(g_{i+1}+g_i)$$
然后:$$ frac {1-k_i}{k_i} * g_i = g_{i+1}$$
设$t_i = frac{1-k_i}{k_i}$,$t_0 = 1$;
我们知道$f_{l-1}=0$(感性理解一下),$f_{r}=1$,所以说$g_l * sum_{ i = l}^{ r } prod_{j = 0}^{ i - 1 }t_j = 1$
展开写出来大概是这样的:$$g_l * (1+t_l+t_l*t_{l+1}+……+t_l*t_{l+1}*……*t_{r-1}) = 1$$
然后线段树维护两个值:一个是$t_i*t_{i+1}*……$,另一个是$t_l+t_l*t_{l+1}+……$。
然后转移就好了。时间复杂度$O(qlogn)$。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N = 100500; template<typename T> inline void read(T&x) { T f = 1,c = 0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } int n,m; double k[N]; struct Pair { double a,b; Pair(){} Pair(double a,double b):a(a),b(b){} Pair operator + (const Pair&x)const{return Pair(a+x.a*b,b*x.b);} }; struct segtree { Pair p[N<<2]; void update(int u) { p[u] = p[u<<1]+p[u<<1|1]; } void build(int l,int r,int u) { if(l==r) { p[u] = Pair(k[l],k[l]); return ; } int mid = (l+r)>>1; build(l,mid,u<<1); build(mid+1,r,u<<1|1); update(u); } void insert(int l,int r,int u,int qx,double d) { if(l==r){p[u]=Pair(k[l],k[l]);return ;} int mid = (l+r)>>1; if(qx<=mid)insert(l,mid,u<<1,qx,d); else insert(mid+1,r,u<<1|1,qx,d); update(u); } Pair query(int l,int r,int u,int ql,int qr) { if(l==ql&&r==qr)return p[u]; int mid = (l+r)>>1; if(qr<=mid)return query(l,mid,u<<1,ql,qr); else if(ql>mid)return query(mid+1,r,u<<1|1,ql,qr); else return query(l,mid,u<<1,ql,mid)+query(mid+1,r,u<<1|1,mid+1,qr); } }tr; int main() { read(n),read(m); ll X,Y; for(int i=1;i<=n;i++) { read(X),read(Y); k[i] = (double)(Y-X)/(X); } tr.build(1,n,1); for(int op,d,l,r,i=1;i<=m;i++) { read(op); if(op==1) { read(d),read(X),read(Y); k[d] = (double)(Y-X)/(X); tr.insert(1,n,1,d,k[d]); }else { read(l),read(r); Pair ans = tr.query(1,n,1,l,r); printf("%.10lf ",1.0/(ans.a+1.0)); } } return 0; }