zoukankan      html  css  js  c++  java
  • BJOI2018链上二次求和——线段树

    BJOI2018 链上二次求和

    思路

    [l,r]的限制可以拆成[1,l-1],[1,r],然后考虑推式子。

    (s_i)(a_i)的前缀和。

    ({ m ans}=sum_{i=1}^{x}sum_{j=i}^{n}s_{j}-s_{j-i})

    (t_i)(s_i)的前缀和。

    ({ m ans}=sum_{i=1}^{x}t_{n}-t_{i-1}-t_{n-i})

    发现如果我们可以区间维护前缀和的前缀和,那么就可以直接区间查询得到答案了。

    考虑一次修改对答案造成的影响,发现对于下标为(i)的点的贡献为一个(ai^{2}+bi+c)形式的多项式,也就是区间加上一个二次函数。

    对于区间加上二次函数,我们可以通过简单的线段树打标记来完成,修改一个点时需要用到二次幂和,直接套用公示即可,标记合并直接相加即可。

    /*=======================================
     * Author : ylsoi
     * Time : 2019.3.31
     * Problem : loj2512
     * E-mail : ylsoi@foxmail.com
     * ====================================*/
    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<" "
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("loj2512.in","r",stdin);
    	freopen("loj2512.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	_=0; T f=1; char c=getchar();
    	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    	for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    	_*=f;
    }
    
    string proc(){
    	ifstream f("/proc/self/status");
    	return string(istreambuf_iterator<char>(f),istreambuf_iterator<char>());
    }
    
    const int maxn=2e5+10;
    const int mod=1e9+7;
    int n,q,s[maxn];
    
    void mul(int &x,int y){
    	x=1ll*x*y%mod;
    }
    void inc(int &x,int y){
    	x+=y;
    	if(x>=mod)x-=mod;
    	else if(x<0)x+=mod;
    }
    
    int qpow(int x,int y=mod-2){
    	int ret=1; x%=mod;
    	while(y){
    		if(y&1)ret=1ll*ret*x%mod;
    		x=1ll*x*x%mod;
    		y>>=1;
    	}
    	return ret;
    }
    
    const int inv2=qpow(2);
    const int inv6=qpow(6);
    
    #define mid ((l+r)>>1)
    #define lc o<<1
    #define rc o<<1|1
    #define lson lc,l,mid
    #define rson rc,mid+1,r
    int sum[maxn<<2],a[maxn<<2],b[maxn<<2],c[maxn<<2];
    
    void build(int o,int l,int r){
    	if(l==r)sum[o]=s[l];
    	else{
    		build(lson),build(rson);
    		sum[o]=(sum[lc]+sum[rc])%mod;
    	}
    }
    
    int S2(int x){return 1ll*x*(x+1)%mod*(2*x+1)%mod*inv6%mod;}
    int S1(int x){return 1ll*x*(x+1)%mod*inv2%mod;}
    
    void pushdown(int o,int l,int r){
    	if(a[o]){
    		inc(sum[lc],1ll*(S2(mid)-S2(l-1))*a[o]%mod),inc(a[lc],a[o]);
    		inc(sum[rc],1ll*(S2(r)-S2(mid))*a[o]%mod),inc(a[rc],a[o]);
    	}
    	if(b[o]){
    		inc(sum[lc],1ll*(S1(mid)-S1(l-1))*b[o]%mod),inc(b[lc],b[o]);
    		inc(sum[rc],1ll*(S1(r)-S1(mid))*b[o]%mod),inc(b[rc],b[o]);
    	}
    	if(c[o]){
    		inc(sum[lc],1ll*(mid-l+1)*c[o]%mod),inc(c[lc],c[o]);
    		inc(sum[rc],1ll*(r-mid)*c[o]%mod),inc(c[rc],c[o]);
    	}
    	a[o]=b[o]=c[o]=0;
    }
    
    void update(int o,int l,int r,int L,int R,int aa,int bb,int cc){
    	if(L>R)return;
    	if(L<=l && r<=R){
    		//debug(l),debug(r)<<endl;
    		//printf("%d %d %d
    ",aa,bb,cc);
    		//debug(sum[o])<<endl;
    		inc(sum[o],1ll*(S2(r)-S2(l-1))*aa%mod),inc(a[o],aa);
    		inc(sum[o],1ll*(S1(r)-S1(l-1))*bb%mod),inc(b[o],bb);
    		inc(sum[o],1ll*(r-l+1)*cc%mod),inc(c[o],cc);
    		//debug(sum[o])<<endl;
    	}
    	else{
    		pushdown(o,l,r);
    		if(L<=mid)update(lson,L,R,aa,bb,cc);
    		if(R>=mid+1)update(rson,L,R,aa,bb,cc);
    		sum[o]=(sum[lc]+sum[rc])%mod;
    	}
    }
    
    int query(int o,int l,int r,int L,int R){
    	if(L>R)return 0;
    	if(L<=l && r<=R)return sum[o];
    	int ret=0;
    	pushdown(o,l,r);
    	if(L<=mid)inc(ret,query(lson,L,R));
    	if(R>=mid+1)inc(ret,query(rson,L,R));
    	return ret;
    }
    
    int solve(int x){
    	return (1ll*query(1,1,n,n,n)*x%mod-query(1,1,n,1,x-1)-query(1,1,n,n-x,n-1))%mod;
    }
    
    int main(){
    	File();
    
    	read(n),read(q);
    	REP(i,1,n)read(s[i]);
    	REP(i,1,n)inc(s[i],s[i-1]);
    	REP(i,1,n)inc(s[i],s[i-1]);
    	build(1,1,n);
    
    	int ty,l,r,x;
    	REP(i,1,q){
    		read(ty);
    		if(ty==1){
    			read(l),read(r),read(x);
    			if(l>r)swap(l,r);
    			update(1,1,n,l,r,1ll*inv2*x%mod,1ll*(3-2*l)*inv2%mod*x%mod,1ll*(2-l)*(1-l)%mod*inv2%mod*x%mod);
    			update(1,1,n,r+1,n,0,1ll*(r-l+1)*x%mod,1ll*(2-l-r)*(r-l+1)%mod*inv2%mod*x%mod);
    		}
    		else{
    			read(l),read(r);
    			printf("%d
    ",((solve(r)-solve(l-1))%mod+mod)%mod);
    		}
    		/*REP(j,1,n)printf("%d ",query(1,1,n,j,j));
    		printf("
    ");*/
    	}
    
    	return 0;
    }
    
    
  • 相关阅读:
    Python高级数据处理与可视化(四)---- 数据存储
    Python高级数据处理与可视化(三)---- Matplotlib图像属性控制 & Pandas作图
    Notepad++
    HDU2819 Swap(二分匹配+输出结果)
    HDU1281 棋盘游戏(二分匹配+找必要的点)
    HDU1083 Courses(二分匹配)
    HDU2444 二分图判断+最大匹配
    HDU1045 Fire Net(二分匹配)
    exam1802 Bounty Hunter II(DAG的最小路径覆盖)
    SDUSTOJ 1801 LIS2(最长上升子序列不同值的数量)
  • 原文地址:https://www.cnblogs.com/ylsoi/p/10633632.html
Copyright © 2011-2022 走看看