【题目】
题目描述:
一个长度为
n
n
n 的序列,一开始序列数的权值都是
0
0
0,有
m
m
m 次操作
支持两种操作:
1
1
1
l
l
l
r
r
r
x
x
x,给区间 [
l
l
l ,
r
r
r ] 内位置为
p
o
s
pos
pos 的数加上
(
p
o
s
−
l
)
∗
x
(pos-l)*x
(pos−l)∗x
0
0
0
l
l
l
r
r
r,查询区间 [
l
l
l ,
r
r
r ] 内的权值和
最终答案对
1
0
9
+
7
10^9+7
109+7 取模。
输入格式:
第一行两个数
n
n
n,
m
m
m,表示序列长度和操作次数
接下来
m
m
m 行,每行描述一个操作,有如下两种情况:
1
1
1
l
l
l
r
r
r
x
x
x,给区间 [
l
l
l ,
r
r
r ] 内位置为
p
o
s
pos
pos 的数加上
(
p
o
s
−
l
)
∗
x
(pos-l)*x
(pos−l)∗x
0
0
0
l
l
l
r
r
r,查询区间 [
l
l
l ,
r
r
r ] 内的权值和
输出格式:
每一个 0 0 0 操作输出一个整数模 1 0 9 + 7 10^9+7 109+7
样例数据:
输入
5 5
0 2 3
1 4 5 1
1 1 5 5
0 1 4
0 2 3
输出
0
30
15
提示:
【数据范围】
对于
30
%
30\%
30% 的数据
n
,
m
n,m
n,m ≤
2000
2000
2000
对于
100
%
100\%
100% 的数据,
n
,
m
n,m
n,m ≤
300000
300000
300000
保证读入的都是非负整数,所有的
x
x
x ≤
10000
10000
10000
【分析】
相当于是区间加上一个等差数列吧
除了维护区间和之外,我们还需要维护每个区间的等差数列的首项和公差
由于是等差数列,用线段树很好合并,首项和公差就直接相加,和的话套公式求和就可以了
然后其他的就是线段树基础操作了
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 300005
#define Mod 1000000007
using namespace std;
int n,m,L,R,x;
int sum[N<<2],begin[N<<2],num[N<<2];
void add(int root,int l,int r,int val,int start)
{
num[root]=(num[root]+val)%Mod;
begin[root]=(begin[root]+start)%Mod;
sum[root]=(sum[root]+(2ll*start+(r-l)*val)*(r-l+1)/2%Mod)%Mod;
}
void pushdown(int root,int l,int r,int mid)
{
if(num[root])
{
add(root<<1,l,mid,num[root],begin[root]);
add(root<<1|1,mid+1,r,num[root],(begin[root]+1ll*num[root]*(mid-l+1)%Mod)%Mod);
num[root]=0,begin[root]=0;
}
}
void modify(int root,int l,int r,int x,int y,int k)
{
if(l>=x&&r<=y)
{
add(root,l,r,k,1ll*(l-L)*k%Mod);
return;
}
int mid=(l+r)>>1;
pushdown(root,l,r,mid);
if(x<=mid) modify(root<<1,l,mid,x,y,k);
if(y>mid) modify(root<<1|1,mid+1,r,x,y,k);
sum[root]=(sum[root<<1]+sum[root<<1|1])%Mod;
}
int query(int root,int l,int r,int x,int y)
{
if(l>=x&&r<=y)
return sum[root];
int ans=0,mid=(l+r)>>1;
pushdown(root,l,r,mid);
if(x<=mid) ans=(ans+query(root<<1,l,mid,x,y))%Mod;
if(y>mid) ans=(ans+query(root<<1|1,mid+1,r,x,y))%Mod;
return ans;
}
int main()
{
freopen("segment.in","r",stdin);
freopen("segment.out","w",stdout);
int s,i;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i)
{
scanf("%d%d%d",&s,&L,&R);
if(s==0) printf("%d\n",query(1,1,n,L,R));
if(s==1) scanf("%d",&x),modify(1,1,n,L,R,x);
}
fclose(stdin);
fclose(stdout);
return 0;
}