游戏
小 R 和室友小 B 在寝室里玩游戏。他们一共玩了 (n) 局游戏,每局游戏的结果要么是小 R 获胜,要么是小 B 获胜。
第 (1) 局游戏小 R 获胜的概率是 (p_1),小 B 获胜的概率是 (1-p_1)。除了第一局游戏之外,每一局游戏小 R 获胜的概率与上一局游戏小 R 是否获胜有关。
具体来说:
如果第 (i-1 (1< ile n)) 局游戏小 R 获胜,那么第 (i) 局游戏小 R 获胜的概率为 (p_i),小 B 获胜的概率为 (1-p_i)。
如果第 (i-1 (1< ile n)) 局游戏小 B 获胜,那么第 (i) 局游戏小 R 获胜的概率为 (q_i),小 B 获胜的概率为 (1-q_i)。
小 D 时常过来看小 R 和小 B 玩游戏,因此他知道某几局游戏的结果。他想知道在他已知信息的条件下,小 R 在 (n) 局游戏中获胜总局数的期望是多少。
小 D 记性不太好,有时他会回忆起某局游戏的结果,并把它加入到已知信息中;有时他会忘记之前某局游戏结果,并把它从已知信息中删除。你的任务是:每当小 D 在已知信息中增加或删除一条信息时,根据小 D 记得的已知信息,帮助小 D 计算小 R 在 (n) 局游戏中获胜总局数的期望是多少。
需要注意的是:如果小 D 忘了一局游戏的结果,之后又重新记起,两次记忆中的游戏结果不一定是相同的。你不需要关心小 D 的记忆是否与实际情况相符,你只需要根据他的记忆计算相应的答案。
对于100%的数据,(1le nle 200000, 1le m le 200000,0 < p_i,q_i < 1)。
题解
贝叶斯公式的运用。
https://www.cnblogs.com/xuruifan/p/7016935.html
https://wearrys.github.io/2017/ctsc2017-game/
根据期望线性性,同样是考虑每个未被确定的游戏的胜率
感性理解一下,显然每个游戏只和两边已确定的结果有关。所以相当于根据已确定的结果划分了若干个区间。每次插入删除就是删去旧区间加入新区间
假设 (X) 两边的已知事件是 (A) 和 (B),根据条件概率,
用线段树维护矩阵就可以很方便地求出分母和分子的总和了。时间复杂度 (O(nlog n))。
struct matrix {float128 v[2][2];};
IN matrix operator+(CO matrix&a,CO matrix&b){
matrix ans;
for(int i=0;i<2;++i)for(int j=0;j<2;++j)
ans.v[i][j]=a.v[i][j]+b.v[i][j];
return ans;
}
IN matrix operator*(CO matrix&a,CO matrix&b){
matrix ans;
for(int i=0;i<2;++i)for(int j=0;j<2;++j)
ans.v[i][j]=a.v[i][0]*b.v[0][j]+a.v[i][1]*b.v[1][j];
return ans;
}
struct node {matrix p,e;};
IN node operator+(CO node&a,CO node&b){
return {a.p*b.p,a.p*b.e+a.e*b.p};
}
CO int N=2e5+10;
float128 p[N],q[N];
int S[N];
node tr[4*N];
#define lc (x<<1)
#define rc (x<<1|1)
#define mid ((l+r)>>1)
void build(int x,int l,int r){
if(l==r){ // l-1 -> l
tr[x].p.v[0][0]=1-q[l],tr[x].p.v[0][1]=q[l];
tr[x].p.v[1][0]=1-p[l],tr[x].p.v[1][1]=p[l];
tr[x].e.v[0][0]=0,tr[x].e.v[0][1]=q[l];
tr[x].e.v[1][0]=0,tr[x].e.v[1][1]=p[l];
return;
}
build(lc,l,mid),build(rc,mid+1,r);
tr[x]=tr[lc]+tr[rc];
}
node query(int x,int l,int r,int ql,int qr){
if(ql<=l and r<=qr) return tr[x];
if(qr<=mid) return query(lc,l,mid,ql,qr);
if(ql>mid) return query(rc,mid+1,r,ql,qr);
return query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr);
}
#undef lc
#undef rc
#undef mid
set<int> st;
int main(){
int n=read<int>(),m=read<int>();
scanf("%*s %Lf",&p[1]);
for(int i=2;i<=n;++i) scanf("%Lf%Lf",&p[i],&q[i]);
S[0]=1,S[n+1]=0;
st.insert(0),st.insert(n+1);
build(1,1,n+1);
function<float128(int,int)> calc=[n](int l,int r){ // (l,r]
node ans=query(1,1,n+1,l+1,r);
return ans.e.v[S[l]][S[r]]/ans.p.v[S[l]][S[r]];
};
float128 ans=calc(0,n+1);
while(m--){
static char opt[10];scanf("%s",opt);
if(opt[0]=='a'){
int i=read<int>();
read(S[i]);
set<int>::iterator it=st.insert(i).first;
set<int>::iterator it_l=it,it_r=it;
--it_l,++it_r;
int l=*it_l,r=*it_r;
ans-=calc(l,r);
ans+=calc(l,i)+calc(i,r);
}
else{
int i=read<int>();
set<int>::iterator it=st.find(i);
set<int>::iterator it_l=it,it_r=it;
--it_l,++it_r;
int l=*it_l,r=*it_r;
st.erase(it);
ans-=calc(l,i)+calc(i,r);
ans+=calc(l,r);
}
printf("%Lf
",ans);
}
return 0;
}