题意
给数列 (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 imes a_j imes 2^{n+i-j-1}}{2^n}$$。
## 题解
$sum_{i=1}^{n-1}sum_{j=i+1}^{n}a_i imes a_j imes 2^{n+i-j-1}$ 可以用线段树来计算。
设管理区间为 $[l,r]$ 的节点为 $i$,设:
$val[i]$ 为数列 $a_l,a_{l+1},...,a_r$ 的总值
$suml[i]=a_l+a_{l+1} imes 2+...+a_r imes 2^{r-l}$
$sumr[i]=a_l imes 2^{r-l}+a_{l+1} imes 2^{r-l-1}+...+a_r$
$siz[i]$ 为 $a_l,a_{l+1},...a_r$ 中非零元素的数量
设 $ls$ 为 $i$ 的左儿子,$rs$ 为 $i$ 的右儿子,那么:
$val[i]=val[ls] imes 2^{siz[rs]}+suml[ls] imes sumr[rs]+val[rs] imes 2^{siz[ls]}$
$suml[i]=suml[ls]+suml[rs] imes 2^{siz[ls]}$
$sumr[i]=sumr[ls] imes 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
",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
",tr.val[1]*inv%mod);
}
return 0;
}
```]