CodeForces 1316F. Battalion Strength【线段树】

传送门

题意

给数列 \(p_1,p_2,...,p_n\),并随时修改,要求在每次修改之后,回答:
将原数列单调非递减排序形成 \(a_1,a_2,...,a_n\),计算
\[\frac{\sum_{i=1}^{n-1}\sum_{j=i+1}^{n}a_i\times a_j\times 2^{n+i-j-1}}{2^n}\]

题解

\(\sum_{i=1}^{n-1}\sum_{j=i+1}^{n}a_i\times a_j\times 2^{n+i-j-1}\) 可以用线段树来计算。
设管理区间为 \([l,r]\) 的节点为 \(i\),设:
\(val[i]\) 为数列 \(a_l,a_{l+1},...,a_r\) 的总值
\(suml[i]=a_l+a_{l+1}\times 2+...+a_r\times 2^{r-l}\)
\(sumr[i]=a_l\times 2^{r-l}+a_{l+1}\times 2^{r-l-1}+...+a_r\)
\(siz[i]\)\(a_l,a_{l+1},...a_r\) 中非零元素的数量
\(ls\)\(i\) 的左儿子,\(rs\)\(i\) 的右儿子,那么:
\(val[i]=val[ls]\times 2^{siz[rs]}+suml[ls]\times sumr[rs]+val[rs]\times 2^{siz[ls]}\)
\(suml[i]=suml[ls]+suml[rs]\times 2^{siz[ls]}\)
\(sumr[i]=sumr[ls]\times 2^{siz[rs]}+sumr[rs]\)
这样维护线段树,可以方便我们对任意节点进行更改,而根节点的 \(val\) 就是答案。
这个题还有点麻烦的是在计算之前要使原数列有序,而删改之后好像数列又无序了。
其实可以先将初始值和所有修改都存下来,然后排序,每个操作对应线段树上的一个节点,这样就可以保证线段树维护的是递增的数列了。
如果要更改一个位置的值,可以先将线段树上原数对应位置归 \(0\),然后更改当前数对应位置的值。

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define ff first
#define ss second
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=3e5+10;
const int mod=1e9+7;
int n,q,idx[N],pos[N*2],now[N*2];
PII p[2*N];
LL po[2*N];

LL qpow(LL x,LL k){
    LL res=1;
    while(k){
        if(k&1) res=res*x%mod;
        k>>=1;x=x*x%mod;
    }
    return res;
}

struct SegTree{
    #define mid ((l+r)>>1)
    LL val[N*8],suml[N*8],sumr[N*8],siz[N*8];
    void upd(int id,int l,int r,int pos,int x){
        if(l==r) {val[id]=0;suml[id]=sumr[id]=x;siz[id]=(bool)x;return;}
        if(pos<=mid) upd(id<<1,l,mid,pos,x);
        else upd(id<<1|1,mid+1,r,pos,x);
        val[id]=(val[id<<1]*po[siz[id<<1|1]]%mod+suml[id<<1]*sumr[id<<1|1]+val[id<<1|1]*po[siz[id<<1]]%mod)%mod;
        suml[id]=(suml[id<<1]+suml[id<<1|1]*po[siz[id<<1]])%mod;
        sumr[id]=(sumr[id<<1]*po[siz[id<<1|1]]+sumr[id<<1|1])%mod;
        siz[id]=siz[id<<1]+siz[id<<1|1];
    }
    #undef mid
}tr;

int main(){
    scanf("%d",&n);
    po[0]=1;
    for(int i=1;i<=n;i++) po[i]=po[i-1]*2%mod;
    for(int i=1;i<=n;i++) scanf("%lld",&p[i].ff),p[i].ss=i;
    scanf("%d",&q);
    for(int i=1;i<=q;i++) scanf("%d%d",&idx[i],&p[i+n].ff),p[i+n].ss=i+n;
    sort(p+1,p+n+q+1);
    for(int i=1;i<=n+q;i++) pos[p[i].ss]=i;
    LL inv=qpow(po[n],mod-2);
    for(int i=1;i<=n+q;i++) if(p[i].ss<=n) {
        now[p[i].ss]=pos[p[i].ss];
        tr.upd(1,1,n+q,i,p[i].ff);
    }
    printf("%lld\n",tr.val[1]*inv%mod);
    for(int i=1;i<=q;i++){
        tr.upd(1,1,n+q,now[idx[i]],0);
        tr.upd(1,1,n+q,pos[n+i],p[pos[n+i]].ff);
        now[idx[i]]=pos[n+i];
        printf("%lld\n",tr.val[1]*inv%mod);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BakaCirno/p/12424307.html