cogs2632. [HZOI 2016]数列操作d

【题目描述】


一个长度为n的序列,一开始序列数的权值都是0,有m次操作

支持两种操作,

1 L R x,给区间[L,R]内位置为pos的数加上(pos-L)*x

0 L R,查询区间[L,R]内的权值和

最终答案对1e9+7取模


【输入格式】

第一行两个数n,m,表示序列长度和操作次数

接下来m行,每行描述一个操作,有如下两种情况:



1 L R x,给区间[L,R]内位置为pos的数加上(pos-L)*x

0 L R,查询区间[L,R]内的权值和



【输出格式】

每一个0操作输出一个整数模1e9+7

【样例输入】

5 5 0 2 3 1 4 5 1 1 1 5 5 0 1 4 0 2 3

【样例输出】

0
30
15 

【提示】

对于30%的数据 n,m<=2000

对于100%的数据,n,m<=300000

保证读入的都是非负整数,所有的x<=10000

【来源】

感谢神犇
非常感谢神犇

非常非常感谢神犇

线段树维护等差数列 维护公差与首项

注意取模

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=300000+10;
const long long MOD=1000000007;
long long fr[maxn*4],ad[maxn*4];
long long summ[maxn*4];
typedef long long ll;
ll ql,qr;
inline void pushdown(int o,ll l,ll r){
	if(l==r)
		return ;
	int mid=(l+r)>>1;
	fr[o<<1]+=fr[o];
	ad[o<<1]+=ad[o];
	fr[o<<1]=(fr[o<<1]+MOD)%MOD;
	ad[o<<1]=(ad[o<<1]+MOD)%MOD;
	summ[o<<1]+=(long long)(fr[o]*(mid-l+1)+MOD)%MOD;
	summ[o<<1]=(summ[o<<1]+MOD)%MOD;
	summ[o<<1]+=(long long)(((mid-l)*ad[o])*(mid-l+1)/2+MOD)%MOD;
	summ[o<<1]=(summ[o<<1]+MOD)%MOD;
	fr[o<<1|1]+=fr[o]+ad[o]*(mid+1-l);
	ad[o<<1|1]+=ad[o];
	fr[o<<1|1]=(fr[o<<1|1]+MOD)%MOD;
	ad[o<<1|1]=(ad[o<<1|1]+MOD)%MOD;
	summ[o<<1|1]+=(long long)((fr[o]+ad[o]*(mid+1-l))*(r-mid)+MOD)%MOD;
	summ[o<<1|1]=(summ[o<<1|1]+MOD)%MOD;
	summ[o<<1|1]+=(long long)(((r-mid-1)*ad[o])*(r-mid)/2+MOD)%MOD;
	summ[o<<1|1]=(summ[o<<1|1]+MOD)%MOD;
	fr[o]=0;
	ad[o]=0;
}
inline void add(int o,ll l,ll r,ll x){
	if(ad[o])
		pushdown(o,l,r);
	if(ql<=l&&r<=qr){
		fr[o]+=(l-ql)*x;
		fr[o]=(fr[o]+MOD)%MOD;
		ad[o]+=x;
		ad[o]=(ad[o]+MOD)%MOD;
		summ[o]+=(long long)(l-ql)*x*(r-l+1);
		summ[o]=(summ[o]+MOD)%MOD;
		summ[o]+=(long long)((r-l)*x)*(r-l+1)/2;
		summ[o]=(summ[o]+MOD)%MOD;
		return ;
	}
	else if(l!=r){
		int mid=(l+r)>>1;
		if(mid>=ql)
			add(o<<1,l,mid,x);
		if(mid<qr)
			add(o<<1|1,mid+1,r,x);
		summ[o]=((summ[o<<1]+summ[o<<1|1])%MOD+MOD)%MOD;
	}
}
inline long long query(int o,ll l,ll r){
	if(ad[o])
		pushdown(o,l,r);
	if(ql<=l&&r<=qr)
		return (summ[o]+MOD%MOD);
	else if(l!=r){
		int mid=(l+r)>>1;
		long long ans=0;
		if(mid>=ql)
			ans+=query(o<<1,l,mid);
		ans=(ans+MOD)%MOD;
		if(mid<qr)
			ans+=query(o<<1|1,mid+1,r);
		ans=(ans+MOD)%MOD;
		return ans;
	}
	return 0;
}
int main(){
	freopen("segment.in","r",stdin);
	freopen("segment.out","w",stdout);
	int n,m;
	scanf("%d %d",&n,&m);
	int opt,x;
	while(m--){
		scanf("%d %d %d",&opt,&ql,&qr);
		if(opt==1){
			scanf("%d",&x);
			add(1,1,n,x);
		}
		else printf("%lld\n",(query(1,1,n)+MOD)%MOD);
	}
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值