Codeforces Round #370 (Div. 2) E. Memory and Casinos

E. Memory and Casinos
time limit per test4 seconds
memory limit per test512 megabytes
inputstandard input
outputstandard output
There are n casinos lined in a row. If Memory plays at casino i, he has probability pi to win and move to the casino on the right (i + 1) or exit the row (if i = n), and a probability 1 - pi to lose and move to the casino on the left (i - 1) or also exit the row (if i = 1).

We say that Memory dominates on the interval i… j if he completes a walk such that,

He starts on casino i.
He never looses in casino i.
He finishes his walk by winning in casino j.
Note that Memory can still walk left of the 1-st casino and right of the casino n and that always finishes the process.

Now Memory has some requests, in one of the following forms:

1 i a b: Set .
2 l r: Print the probability that Memory will dominate on the interval l… r, i.e. compute the probability that Memory will first leave the segment l… r after winning at casino r, if she starts in casino l.
It is guaranteed that at any moment of time p is a non-decreasing sequence, i.e. pi ≤ pi + 1 for all i from 1 to n - 1.

Please help Memory by answering all his requests!

Input
The first line of the input contains two integers n and q(1 ≤ n, q ≤ 100 000), — number of casinos and number of requests respectively.

The next n lines each contain integers ai and bi (1 ≤ ai < bi ≤ 109) — is the probability pi of winning in casino i.

The next q lines each contain queries of one of the types specified above (1 ≤ a < b ≤ 109, 1 ≤ i ≤ n, 1 ≤ l ≤ r ≤ n).

It’s guaranteed that there will be at least one query of type 2, i.e. the output will be non-empty. Additionally, it is guaranteed that p forms a non-decreasing sequence at all times.

Output
Print a real number for every request of type 2 — the probability that boy will “dominate” on that interval. Your answer will be considered correct if its absolute error does not exceed 10 - 4.

Namely: let’s assume that one of your answers is a, and the corresponding answer of the jury is b. The checker program will consider your answer correct if |a - b| ≤ 10 - 4.

Example
input
3 13
1 3
1 2
2 3
2 1 1
2 1 2
2 1 3
2 2 2
2 2 3
2 3 3
1 2 2 3
2 1 1
2 1 2
2 1 3
2 2 2
2 2 3
2 3 3
output
0.3333333333
0.2000000000
0.1666666667
0.5000000000
0.4000000000
0.6666666667
0.3333333333
0.2500000000
0.2222222222
0.6666666667
0.5714285714
0.6666666667

题意:给出n个的赌场,和每个赌场的胜率,胜利前进一格,否则退回一格,问从l出发,第一次走出l,r是从r出去的概率。
用线段树维护区间l,r从l出发,l走出去的概率pl,r走出去的概率pr,和从r出发,从l走出去的概率rpl,从r走出去的概率rpr,区间合并公式:已知l1,r1和l2,r2,r1+1=l2,求区间l1,r2;
pr(l1,r2) = pr(l1,r1)pr(l2,r2)(1/(rpr(l1,r1)*pl(l2,r2));
rpl(l1,r2) = rpl(l1,r1)rpl(l2,r2)(1/(rpr(l1,l2)*pl(l2,r2));
证明1:点与他前面的区间合并,
已知l,r,从l出去,r走出去的概率为pr,l-1的胜率为px,则第一次从l-1走到l,有pr从r出去,pl走回l-1,然后走回l-1的点还会对结果做出贡献,然后下一次的贡献是走到l-1,又走到r的部分,每次走到l位置都会对结果做出一部分贡献,可以观察出每次走到l位置的概率是等比数列,所以可以求出l-1走到r的概率,
证明2:区间与区间合并
区间合并的时候要维护两个值,从左端出发,和从右端出发,根据证明1;模拟一下,就可以理解证明2了;

#include
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1


using namespace std;
const int N= 1e5+100;
const int B = 333;
struct node{
    double pl,pr;
    double rpl,rpr;
};
node sum[N<<2];
int a[N],b[N];
int n,q;
node solve(node a,node b){
    node now;
    now.pr = a.pr/(1-a.rpr*b.pl)*b.pr;
    now.pl = 1 - now.pr;
    now.rpl = b.rpl/(1-a.rpr*b.pl)*a.rpl;
    now.rpr = 1 - now.rpl;
    return now;
}
void pushup(int rt){
    sum[rt] = solve(sum[rt<<1],sum[rt<<1|1]);
}

void build(int l,int r,int rt){
    if(l == r){
        double now = a[l]*1.0/b[l];
        sum[rt].pl = 1-now;
        sum[rt].pr = now;
        sum[rt].rpl = 1-now;
        sum[rt].rpr = now;
        //cout<< l << ' '<< r << ' ' << rt << ' '<< sum[rt].pr<
        return ;
    }
    int mid = (l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
    //cout <
}
node query(int L,int R,int l,int r,int rt){
    if(L <= l && R >= r){
        return sum[rt];
    }
    int mid = (l+r)>>1;
    node now{0,1};
    if(mid < R) now = query(L,R,rson);
    if(mid >= L) now = solve(query(L,R,lson),now);
    return now;
}
void update(int x,double f,int l,int r,int rt){
    if(l == r){
        sum[rt].pr = f;
        sum[rt].pl = 1-f;
        sum[rt].rpr = f;
        sum[rt].rpl = 1-f;
        return;
    }
    int mid = (l+r)>>1;
    if(mid >= x) update(x,f,lson);
    else update(x,f,rson);
    pushup(rt);
}

int main(){
    scanf("%d %d",&n,&q);
    for(int i = 1;i <= n;i ++){
        scanf("%d %d",&a[i],&b[i]);
    }
    build(1,n,1);
    node a = sum[4],b = sum[5],c = sum[3];
    node now = solve(b,c);
    now = solve(a,now);
    //cout << now.pr <<' ' << now.pl << endl;
    for(int i=  1;i <= q;i ++){
        int op;
        scanf("%d",&op);
        if(op == 1){
            int x,a,b;
            scanf("%d %d %d",&x,&a,&b);
            update(x,a*1.0/b,1,n,1);
        }
        else {
            int l,r;
            scanf("%d %d",&l,&r);
            node ans = query(l,r,1,n,1);
            printf("%.10f\n",ans.pr);
        }
    }
    return 0;
}

你可能感兴趣的:(算法理解)