Codeforces712E

传送门 here

题意:

有n个赌场,第i个赌场的胜率为$ P_i$,在第i个赌场若取胜则到达第$ i+1$个赌场,反之到达第$ i-1$个赌场

定义统治赌场$ L...R$为从赌场$ L$开始,从赌场$ R+1$结束且期间没有到达过$ L$前面的赌场(没有在赌场$ L$输过)

有$ q$次操作,修改一个赌场的胜率或者询问统治赌场$ L...R$的概率

这题真的很妙啊...

我们定义$ f(i)$为从i走到目标地点的概率

显然当询问$ L...R$时有$ f(L-1)=0,f(R+1)=1$

根据题意有$ f(i)=P_if(i+1)+(1-P_i)f(i-1)$

移项得$ f(i)-f(i-1)=P_if(i+1)+(1-1-P_i)f(i-1)=P_i(f(i+1)-f(i-1))$

定义$ g(i)=f(i)-f(i-1)$

则有$ g(i)=P_i(f(i+1)-f(i-1))$

容易发现$ g(L)=f(L)$也就是所要求的答案

计算$ g(i+1)+g(i)=f(i+1)-f(i)+f(i)-f(i-1)=f(i+1)-f(i-1)=\frac{1}{P_i}g(i)$

因而有$ g(i+1)=\frac{1-P_i}{P_i}g(i)$

根据g的定义有$ \sum\limits_{i=L}^Rg(i)=f(R+1)-f(L-1)=1$

我们又知道$ g(i+1)$和$ g(i)$的比值关系,设为$ t_i$

则有$ g(L)*(1+t_L+t_Lt_{L+1}+...+t_{L}*...*t_{R})=1$

就可以用线段树维护t的信息计算结果了

由于只需要四位精度,因此当括号内的数超过$ 10000$即可跳出避免爆double

my code:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rt register int
#define ll long long
#define r read()
using namespace std;
ll read()
{
    ll x = 0; int zf = 1; char ch;
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}
int i,j,k,m,n,x,y,z,cnt,all,num;
double p[100010],val[100010],qz[100010];
struct segment_tree{
    int L,R;double val,ji;
}a[400010];
void build(const int x,const int L,const int R)
{
    a[x].L=L;a[x].R=R;
    if(L==R)
    {
        a[x].val=a[x].ji=val[L];
        return;
    }
    const int mid=L+R>>1;
    build(x<<1,L,mid);build(x<<1|1,mid+1,R);
    a[x].val=a[x<<1].val+a[x<<1|1].val*a[x<<1].ji;
    a[x].ji=a[x<<1].ji*a[x<<1|1].ji;
}
void change(const int x,const int L,const double val)
{
    if(a[x].L==a[x].R)
    {
        a[x].val=a[x].ji=val;
        return;
    }
    L<=a[x].L+a[x].R>>1?change(x<<1,L,val):change(x<<1|1,L,val);
    a[x].val=a[x<<1].val+a[x<<1|1].val*a[x<<1].ji;
    a[x].ji=a[x<<1].ji*a[x<<1|1].ji;
}
double ansa,ansb;
void query(const int x,const int L,const int R)
{
    if(ansa>10000)return;
    if(a[x].L>R||a[x].R<L)return;
    if(a[x].L>=L&&a[x].R<=R)
    {
        ansa+=a[x].val*ansb;
        ansb*=a[x].ji;
        return;
    }
    query(x<<1,L,R);query(x<<1|1,L,R);
}
int main()
{
    n=r;m=r;
    for(rt i=1;i<=n;i++)
    {
        x=r;y=r;
        p[i]=(double)x/(double)y;
        val[i]=(1-p[i])/p[i];
    }
    build(1,1,n);
    while(m--)
    {
        int opt=r;
        if(opt==2)
        {
            int L=r,R=r;ansa=0;ansb=1;query(1,L,R);
            printf("%.6f\n",1/(ansa+1));
        }
        else
        {
            int L=r;x=r;y=r;
            double t=(double)x/(double)y;
            change(1,L,(1-t)/t);
            p[L]=t;
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/DreamlessDreams/p/9030968.html