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 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; } ```]

原文地址:https://www.cnblogs.com/BakaCirno/p/12424307.html