期望线性性+线段树双tag标记——cf895E

/*
从区间[l1,r1]取出一个数,这个数的期望值为 e1=(sum[r1]-sum[l1-1])/(r1-l1+1)
同理从区间[l2,r2]里取出一个数,这个数期望为 e2=(sum[r2]-sum[l2-1])/(r2-l2+1)
根据期望线性性,[l1,r1]里每个数被选中的概率是1/len1
          所以一次交换后该区间的a[i] ->  (len1-1)/len1*a[i]+1/len1*e2
          同理[l2,r2]里的 a[i] -> (len2-1)/len2*a[i]+1/len2*e1 
用一个线段树来维护sum,两个tag:mul和add 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 200005

int n,a[N],q; 

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
double sum[N<<2],mul[N<<2],add[N<<2];
void pushdown(int l,int r,int rt){
    int m=l+r>>1;
    sum[rt<<1]*=mul[rt];sum[rt<<1]+=(m-l+1)*add[rt];
    sum[rt<<1|1]*=mul[rt];sum[rt<<1|1]+=(r-m)*add[rt];
    mul[rt<<1]*=mul[rt];
    mul[rt<<1|1]*=mul[rt];
    add[rt<<1]*=mul[rt];add[rt<<1]+=add[rt];
    add[rt<<1|1]*=mul[rt];add[rt<<1|1]+=add[rt];
    mul[rt]=1;add[rt]=0;
}
void build(int l,int r,int rt){
    mul[rt]=1;add[rt]=0;
    if(l==r){sum[rt]=a[l];return;}
    int m=l+r>>1;
    build(lson);build(rson);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int L,int R,double MUL,double ADD,int l,int r,int rt){
    if(L<=l && R>=r){
        sum[rt]*=MUL;sum[rt]+=ADD*(r-l+1);
        mul[rt]*=MUL;
        add[rt]*=MUL;add[rt]+=ADD;
        return;
    }
    pushdown(l,r,rt);
    int m=l+r>>1;
    if(L<=m)update(L,R,MUL,ADD,lson);
    if(R>m)update(L,R,MUL,ADD,rson);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
double query(int L,int R,int l,int r,int rt){
    if(L<=l && R>=r)return sum[rt];
    pushdown(l,r,rt);
    int m=l+r>>1;
    double res=0;
    if(L<=m)res+=query(L,R,lson);
    if(R>m)res+=query(L,R,rson);
    return res;
}

int main(){
    cin>>n>>q;
    for(int i=1;i<=n;i++)cin>>a[i];
    build(1,n,1);
    while(q--){
        int op,l1,l2,r1,r2,len1,len2;
        cin>>op;
        if(op==2){
            scanf("%d%d",&l1,&r1);
            cout<<query(l1,r1,1,n,1)<<'\n';
        }
        else {
            scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
            len1=r1-l1+1;
            len2=r2-l2+1;
            double sum1=query(l1,r1,1,n,1);
            double sum2=query(l2,r2,1,n,1);
            double e1=sum1/len1;
            double e2=sum2/len2;
            double mul1=1.0*(len1-1)/len1;
            double mul2=1.0*(len2-1)/len2;
            double add1=1.0/len1*e2;
            double add2=1.0/len2*e1;
            update(l1,r1,mul1,add1,1,n,1);
            update(l2,r2,mul2,add2,1,n,1);
        }
    }
    
} 

 

posted on 2020-02-11 17:30  zsben  阅读(143)  评论(0编辑  收藏  举报

导航