[CF1316F] Battalion Strength

定义一个 (n) 元序列 (p_i),如果 (n=1),则序列权值为 (0),否则序列权值就是原序列排序后相邻两项乘积的和。现在等概率地选出一个子序列,问它的权值的期望是多少。支持动态单点修改。

Solution

对于静态情况,答案为

[sum_{i=1}^n sum_{j=i+1}^n frac{p_i p_j}{2^{j-i+1}} ]

考虑用线段树维护,对于区间 ([l,r]),我们设 (val) 为当前区间权值,(lv=sum_{i=l}^r p_i2^{i-l})(rv=sum_{i=l}^r p_i/2^{i-l+1})(sz) 是当前区间内数的个数,则

[val=val_L+val_R+frac{1}{2} vl_Lvr_R/2^{sz_L} \ sz=sz_L+sz_R \ vl=vl_L+vl_R2^{sz_L} \ vr=vr_L+vr_R/2^{sz_L} ]

对于单点 (a),它的 (val=0, sz=1, vl=a, vr=a/2)

考虑到序列中有重复元素,我们先将所有元素(包括修改的)一起读进来排序,然后将原始的先激活,修改后的先不激活((val=0,sz=0,vl=0,vr=0)),一起挂在线段树上

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1000005;
const int mod =1e+9+7;
const int dbg = 0;

struct item {
    int v,x,t;
    bool operator < (const item &b) {
        return v < b.v;
    }
} I[N];
int n,m,seq[N],src[N],m1[N],m2[N],pos[N],p[N],iqp[N],qp[N];

int qpow(int p,int q) {
    return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;
}

int inv(int p) {
    return qpow(p,mod-2);
}

struct node {
    int val,sz,vl,vr;
} a[N*3];

node merge(node l,node r) {
    node ret;
    ret.val=(l.val+r.val+l.vl*r.vr%mod*iqp[l.sz]%mod)%mod;
    ret.sz=l.sz+r.sz;
    ret.vl=(l.vl+r.vl*qp[l.sz])%mod;
    ret.vr=(l.vr+r.vr*iqp[l.sz])%mod;
    return ret;
}

void open(int p,int l,int r,int x) {
    if(l==r) {
        a[p]={0,1,I[x].v,I[x].v*inv(2)%mod};
    }
    else {
        if(x<=(l+r)/2) open(p*2,l,(l+r)/2,x);
        else open(p*2+1,(l+r)/2+1,r,x);
        a[p]=merge(a[p*2],a[p*2+1]);
    }
}

void open(int x) {
    if(dbg) cout<<"open "<<x<<endl;
    open(1,1,n+m,x);
}

void close(int p,int l,int r,int x) {
    if(l==r) {
        a[p]={0,0,0,0};
    }
    else {
        if(x<=(l+r)/2) close(p*2,l,(l+r)/2,x);
        else close(p*2+1,(l+r)/2+1,r,x);
        a[p]=merge(a[p*2],a[p*2+1]);
    }
}

void close(int x) {
    if(dbg) cout<<"close "<<x<<endl;
    close(1,1,n+m,x);
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=0;i<=1e6;i++) {
        iqp[i]=inv(qpow(2,i));
        qp[i]=qpow(2,i);
    }
    for(int i=1;i<=n;i++) {
        cin>>p[i];
        I[i].v=p[i];
        I[i].x=i;
        I[i].t=0;
    }
    cin>>m;
    for(int i=1;i<=m;i++) {
        int t1,t2;
        cin>>t1>>t2;
        m1[i]=t1;
        m2[i]=t2;
        I[n+i].v=t2;
        I[n+i].x=i;
        I[n+i].t=1;
    }
    sort(I+1,I+n+m+1);
    for(int i=1;i<=n+m;i++) {
        src[i]=I[i].v;
        if(I[i].t==0) {
            seq[I[i].x]=i;
        }
        else {
            pos[I[i].x]=i;
        }
    }
    for(int i=1;i<=n;i++) {
        open(seq[i]);
    }
    cout<<a[1].val<<endl;
    for(int i=1;i<=m;i++) {
        close(seq[m1[i]]);
        open(pos[i]);
        seq[m1[i]]=pos[i];
        cout<<a[1].val<<endl;
    }
}

原文地址:https://www.cnblogs.com/mollnn/p/12463644.html