zoukankan      html  css  js  c++  java
  • bzoj 5291: [Bjoi2018]链上二次求和

    Description

    有一条长度为n的链(1≤i<n,点i与点i+1之间有一条边的无向图),每个点有一个整数权值,第i个点的权值是
    a_i。现在有m个操作,每个操作如下:
    操作1(修改):给定链上两个节点u、v和一个整数d,表示将链上u到v唯一的简单路径上每个点权值都加上d。
    操作2(询问):给定两个正整数L、r,表示求链上所有节点个数大于等于L且小于等于r的简单路径节点权值和之和。
    由于答案很大,只用输出对质数1000000007取模的结果即可。
    一条节点个数为k的简单路径节点权值和为这条上所有k个节点(包括端点)的权值之和,
    而本题中要求是对所有满足要求的简单路径,求这一权值和的和。
    由于是无向图,路径也是无向的,即点1到点2的路径与点2到点1的路径是同一条,不要重复计算。

    Solution

    开始想考虑每个点的贡献,然后发现要分三段讨论,并且维护的东西有点多,写不下去了
    最后直接模拟题意:
    (s_i)(a_i) 的前缀和, (ss_i)(s_i) 的前缀和
    (sum_{k=l}^rsum_{i=k}^n (s_i-s_{i-k}))
    (sum_{k=l}^r (sum_{i=k}^{n}s_i-sum_{i=0}^{n-k}s_i))
    (sum_{k=l}^r (ss_n-ss_{k-1}-ss_{n-k}))
    ((r-l+1)*ss_n-sum_{k=l-1}^{r-1}ss_k-sum_{k=n-r}^{n-l}ss_k)

    线段树维护 (ss) 就好了
    关于修改:
    分两段考虑:
    (l<=i<=r),(ss_i) 加上 (d*frac{(i-l+1)*(i-l+2)}{2})
    (r<i<=n), (ss_i) 加上 (d*(frac{(r-l+1)*(r-l+2)}{2}+(r-l+1)*(i-r)*d))
    分别是关于 (i) 的二次函数和一次函数
    维护系数 (a,b,c) 就好了

    #include<bits/stdc++.h>
    #define ls (o<<1)
    #define rs (o<<1|1)
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    const int N=2e5+10,mod=1e9+7,inv=166666668,inv2=500000004;
    int n,Q,a[N],s[N],ss[N],tr[N*4],A[N*4],B[N*4],C[N*4];
    int la,lb,lc;
    inline int S1(int l,int r){return (1ll*(l+r)*(r-l+1)>>1)%mod;}
    inline int S2(int l,int r){
    	int rr=1ll*r*(r+1)%mod*((r<<1)+1)%mod;l--;
    	int ll=1ll*l*(l+1)%mod*((l<<1)+1)%mod;
    	return 1ll*(rr-ll+mod)*inv%mod;
    }
    inline void upd(int o){tr[o]=(tr[ls]+tr[rs])%mod;}
    inline void build(int l,int r,int o){
    	if(l==r){tr[o]=ss[l];return ;}
    	int mid=(l+r)>>1;
    	build(l,mid,ls);build(mid+1,r,rs);
    	upd(o);
    }
    inline void pushdown(int o,int l,int r){
    	if(!A[o]&&!B[o]&&!C[o])return ;
    	int mid=(l+r)>>1;
    	A[ls]=(A[ls]+A[o])%mod;B[ls]=(B[ls]+B[o])%mod;C[ls]=(C[ls]+C[o])%mod;
    	A[rs]=(A[rs]+A[o])%mod;B[rs]=(B[rs]+B[o])%mod;C[rs]=(C[rs]+C[o])%mod;
    	
    	tr[ls]=(tr[ls]+1ll*S2(l,mid)*A[o])%mod;
    	tr[ls]=(tr[ls]+1ll*S1(l,mid)*B[o])%mod;
    	tr[ls]=(tr[ls]+1ll*(mid-l+1)*C[o])%mod;
    	tr[rs]=(tr[rs]+1ll*S2(mid+1,r)*A[o])%mod;
    	tr[rs]=(tr[rs]+1ll*S1(mid+1,r)*B[o])%mod;
    	tr[rs]=(tr[rs]+1ll*(r-mid)*C[o])%mod;
    
    	A[o]=B[o]=C[o]=0;
    }
    inline void mdf(int l,int r,int o,int sa,int se){
    	if(sa<=l && r<=se){
    		A[o]=(A[o]+la)%mod;B[o]=(B[o]+lb)%mod;C[o]=(C[o]+lc)%mod;
    		tr[o]=(tr[o]+1ll*S2(l,r)*la)%mod;
    		tr[o]=(tr[o]+1ll*S1(l,r)*lb)%mod;
    		tr[o]=(tr[o]+1ll*(r-l+1)*lc)%mod;
    		return ;
    	}
    	pushdown(o,l,r);
    	int mid=(l+r)>>1;
    	if(se<=mid)mdf(l,mid,ls,sa,se);
    	else if(sa>mid)mdf(mid+1,r,rs,sa,se);
    	else mdf(l,mid,ls,sa,mid),mdf(mid+1,r,rs,mid+1,se);
    	upd(o);
    }
    inline int qry(int l,int r,int o,int sa,int se){
    	if(sa<=l && r<=se)return tr[o];
    	pushdown(o,l,r);
    	int mid=(l+r)>>1;
    	if(se<=mid)return qry(l,mid,ls,sa,se);
    	if(sa>mid)return qry(mid+1,r,rs,sa,se);
    	return (qry(l,mid,ls,sa,mid)+qry(mid+1,r,rs,mid+1,se))%mod;
    }
    int main(){
    	freopen("pp.in","r",stdin);
    	freopen("pp.out","w",stdout);
    	cin>>n>>Q;
    	for(int i=1;i<=n;i++)
    		gi(a[i]),s[i]=(s[i-1]+a[i])%mod,ss[i]=(ss[i-1]+s[i])%mod;
    	build(1,n,1);
    	int op,x,y,z;
    	while(Q--){
    		gi(op);gi(x);gi(y);
    		if(x>y)swap(x,y);
    		if(op==1){
    			gi(z);
    			z=1ll*z*inv2%mod;
    			la=z;lb=1ll*(3-2*x)*z%mod;lc=1ll*z*((1ll*x*x-3*x+2)%mod)%mod;
    			if(lb<0)lb+=mod;if(lc<0)lc+=mod;
    			mdf(1,n,1,x,y);
    			if(y<n){
    				z=1ll*z*2%mod;
    				la=0;lb=1ll*(y-x+1)*z%mod;
    				lc=(1ll*z*((1ll*(y-x+1)*(y-x+2)/2-1ll*(y-x+1)*y)%mod))%mod;
    				if(lc<0)lc+=mod;
    				mdf(1,n,1,y+1,n);
    			}
    		}
    		else{
    			int ans=1ll*(y-x+1)*qry(1,n,1,n,n)%mod;
    			if(y-1>0)ans=(1ll*ans-qry(1,n,1,max(x-1,1),y-1)+mod)%mod;
    			if(n-x>0)ans=(1ll*ans-qry(1,n,1,max(n-y,1),n-x)+mod)%mod;
    			printf("%d
    ",ans);
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    winfrom 获取当前系统时间
    netcore3.1API+efcore快速搭建
    php
    php
    php
    php-array的相关函数使用
    php-正则表达式
    vim的复制与粘贴
    vim的多窗口和文件切换操作
    laravel教程中出现500问题
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9077852.html
Copyright © 2011-2022 走看看