zoukankan      html  css  js  c++  java
  • 【BJOI2018】【BZOJ2591】—链上二次求和(线段树维护二次函数)

    传送门

    开始还是挺好想的,就是求前缀和的前缀和
    SS表示前缀和,则
    ans=k=lri=kn(SkSik)ans=sum_{k=l}^{r}sum_{i=k}^n(S_k-S_{i-k})

    =k=lr(i=knSii=0nkSi)=sum_{k=l}^{r}(sum_{i=k}^{n}S_i-sum_{i=0}^{n-k}S_i)

    SSSS表示SS的前缀和

    ans=k=lr(SSnSSk1SSnk)ans=sum_{k=l}^{r}(SS_n-SS_{k-1}-SS_{n-k})
    =(rl+1)SSni=l1r1SSii=nlnrSSi=(r-l+1)SS_n-sum_{i=l-1}^{r-1}SS_i-sum_{i=n-l}^{n-r}SS_i

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

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

    i[l,r]iin[l,r]
    SSi+=(il+1)(il+2)2kSS_i+=frac{(i-l+1)*(i-l+2)}{2}*k

    i[r+1,n]iin [r+1,n]
    SSi+=(len(len+1)2+len(ir))kSS_i+=(frac{len*(len+1)}{2}+len*(i-r))*k

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

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

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define int long long
    inline 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<des)update(rc,mid+1,r,st,des,a1,b1,c1);
    	pushup(u);
    }
    ll query(int u,int l,int r,int st,int des){
    	if(st<=l&&r<=des)return tr[u];
    	ll res=0;pushdown(u,l,r);
    	if(st<=mid)res+=query(lc,l,mid,st,des);
    	if(mid<des)res+=query(rc,mid+1,r,st,des);
    	pushup(u);
    	return res%mod;
    }
    inline void modify(int l,int r,ll k){
    	if(l>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<<ask(l,r)<<'
    ';
    	}
    }
    
  • 相关阅读:
    parseInt 的第二个参数
    htm Dom对象与 Xml Dom对象的理解
    js 立即执行函数,() .则前面的function 是表达式,不能是函数申明
    Promise A 规范的一个简单的浏览器端实现
    css3,环绕圆环 loading,小组件
    有用的小程序的总结
    STM32定时器的小问题总结
    stm32 串口发送数据第一字节丢失
    嵌入式C语言编程小知识总结
    STM32多通道ADC操作
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145626.html
Copyright © 2011-2022 走看看