博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BJOI2018】【BZOJ2591】—链上二次求和(线段树维护二次函数)
阅读量:5090 次
发布时间:2019-06-13

本文共 2886 字,大约阅读时间需要 9 分钟。

开始还是挺好想的,就是求前缀和的前缀和

SSS表示前缀和,则
ans=∑k=lr∑i=kn(Sk−Si−k)ans=\sum_{k=l}^{r}\sum_{i=k}^n(S_k-S_{i-k})ans=k=lri=kn(SkSik)

=∑k=lr(∑i=knSi−∑i=0n−kSi)=\sum_{k=l}^{r}(\sum_{i=k}^{n}S_i-\sum_{i=0}^{n-k}S_i)=k=lr(i=knSii=0nkSi)

SSSSSS表示SSS的前缀和

ans=∑k=lr(SSn−SSk−1−SSn−k)ans=\sum_{k=l}^{r}(SS_n-SS_{k-1}-SS_{n-k})ans=k=lr(SSnSSk1SSnk)

=(r−l+1)SSn−∑i=l−1r−1SSi−∑i=n−ln−rSSi=(r-l+1)SS_n-\sum_{i=l-1}^{r-1}SS_i-\sum_{i=n-l}^{n-r}SS_i=(rl+1)SSni=l1r1SSii=nlnrSSi

发现我们只需要维护一个SSSSSS的区间和

再考虑一次修改对答案的影响

i∈[l,r]i\in[l,r]i[l,r]

SSi+=(i−l+1)∗(i−l+2)2∗kSS_i+=\frac{(i-l+1)*(i-l+2)}{2}*kSSi+=2(il+1)(il+2)k

i∈[r+1,n]i\in [r+1,n]i[r+1,n]

SSi+=(len∗(len+1)2+len∗(i−r))∗kSS_i+=(\frac{len*(len+1)}{2}+len*(i-r))*kSSi+=(2len(len+1)+len(ir))k

拆开后发现是一个二次函数ai2+bi+cai^2+bi+cai2+bi+c的形式,可以维护一下一次修改的a,b,ca,b,ca,b,c

用线段树就可以了

注意有除法,可以先不除2,把所有乘2,最后再乘一个逆元就可以了

#include
using namespace std;#define ll long long#define int long longinline int read(){
char ch=getchar(); int res=0,f=1; while(!isdigit(ch)){
if(ch=='-')f=-f;ch=getchar();} while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar(); return res*f;} const int N=200005;const ll mod=1e9+7;const ll inv2=5e8+4;int n,m;ll ss[N],f1[N],f2[N],a[N<<2],b[N<<2],c[N<<2],tr[N<<2];#define lc (u<<1)#define rc ((u<<1)|1)#define mid ((l+r)>>1)inline void pushup(int u){
tr[u]=(tr[lc]+tr[rc])%mod;}inline void pushnow(int u,int l,int r,ll a1,ll b1,ll c1){
(a[u]+=a1)%=mod,(b[u]+=b1)%=mod,(c[u]+=c1)%=mod; (tr[u]+=(a1*(f2[r]-f2[l-1])%mod)+b1*(f1[r]-f1[l-1])%mod+c1*(r-l+1)%mod)%=mod;}inline void pushdown(int u,int l,int r){
if(!a[u]&&!b[u]&&!c[u])return; pushnow(lc,l,mid,a[u],b[u],c[u]); pushnow(rc,mid+1,r,a[u],b[u],c[u]); a[u]=b[u]=c[u]=0;}void build(int u,int l,int r){
if(l==r){
tr[u]=ss[l];return;} build(lc,l,mid),build(rc,mid+1,r); pushup(u);}void update(int u,int l,int r,int st,int des,ll a1,ll b1,ll c1){
if(st<=l&&r<=des){
pushnow(u,l,r,a1,b1,c1);return;} pushdown(u,l,r); if(st<=mid)update(lc,l,mid,st,des,a1,b1,c1); if(mid
r)swap(l,r); ll a1=k,b1=(3-2*l+mod)%mod*k%mod,c1=((l*l%mod-3*l+2)%mod+mod)%mod*k%mod; update(1,0,n,l,r,a1,b1,c1); if(r==n)return;// ll len=r-l+1; a1=0,b1=len*k*2%mod,c1=(len*(len+1-2*r)%mod+mod)%mod*k%mod; update(1,0,n,r+1,n,a1,b1,c1);}inline ll ask(int l,int r){
ll res=((1ll*(r-l+1)*query(1,0,n,n,n)%mod-query(1,0,n,l-1,r-1)-query(1,0,n,n-r,n-l))%mod+mod)%mod; return res*inv2%mod;}signed main(){
n=read(),m=read(); for(int i=1;i<=n;i++)(ss[i]=ss[i-1]+read())%=mod; for(int i=1;i<=n;i++)(ss[i]+=ss[i-1])%mod; for(int i=1;i<=n;i++)(ss[i]*=2)%=mod,f1[i]=(f1[i-1]+i)%mod,f2[i]=(f2[i-1]+1ll*i*i%mod)%mod; build(1,0,n); while(m--){
int op=read(); int l=read(),r=read(); if(op==1)modify(l,r,read()); else cout<
<<'\n'; }}

转载于:https://www.cnblogs.com/stargazer-cyk/p/11145626.html

你可能感兴趣的文章