参考博客,作者:dreaming__ldx,来源:CSDN
【题目描述】
一个长度为n的序列,一开始序列数的权值都是0,有m次操作
支持两种操作:
1 L R x,给区间[L,R]内位置为pos的数加上(pos-L)*x
0 L R,查询区间[L,R]内的权值和
最终答案对109+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
【思路】 对于等差数列,注意到它是可以合并的。
比如两个等长的等差数列。一个等差数列S1,第一项为A1,公差为t1,另一个等差数列S2,第一项为A2,公差为t2。
那么把S1和S2加起来,就变成了一个第一项为(A1+A2),公差为(t1+t2)的新的等差数列。
现在只要我们知道等差数列的首项,公差和长度,就能求出数列的和。
那么对于每个区间[L,R],用两个标记维护一下这个区间的首项,公差就行了。标记是可以合并的。
注意:这样做的前提是标记具有可合并性。反例:区间加等比数列
求和就是(首+末)*项数 /2。把数据带进去就是(首+(首+(项数-1)*公差))*(R-L+1) /2。
#include<bits/stdc++.h>
#define lc (root<<1)
#define rc (root<<1|1)
#define mid ((T[root].l+T[root].r)>>1)
#define ll long long
using namespace std;
const int maxn=3e5+5;
const ll mod=1e9+7;
int n,m,op,LL,RR,Val;
struct node{
node(){l=r=sum=add=fir=0;}
int l,r;
ll sum,add,fir;
}T[maxn<<2];
inline void pushup(int root){T[root].sum=(T[lc].sum+T[rc].sum)%mod;}
inline void pushadd(int root,ll fir,ll v){
(T[root].add+=v)%=mod,(T[root].fir+=fir)%=mod;
(T[root].sum+=(T[root].r-T[root].l+1)*(2*fir+(T[root].r-T[root].l)*v)/2)%=mod;
}
inline void pushdown(int root){
if(T[root].add){
pushadd(lc,T[root].fir,T[root].add);
pushadd(rc,T[root].fir+T[root].add*(mid-T[root].l+1),T[root].add);
T[root].add=0,T[root].fir=0;
}
}
void build(int root,int l,int r){
T[root].l=l,T[root].r=r;
if(l==r) return;
build(lc,l,mid),build(rc,mid+1,r);
}
void update(int root,int L,int R,ll v){
if(L<=T[root].l&&R>=T[root].r){
pushadd(root,v*(T[root].l-LL),v);
return;
}
pushdown(root);
if(L<=mid) update(lc,L,R,v);
if(R>mid) update(rc,L,R,v);
pushup(root);
}
ll query(int root,int L,int R){
if(L<=T[root].l&&R>=T[root].r) return T[root].sum;
pushdown(root);
ll ret=0;
if(L<=mid) (ret+=query(lc,L,R))%=mod;
if(R>mid) (ret+=query(rc,L,R))%=mod;
return ret%mod;
}
inline void read(int &x){
x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
}
int main(){
freopen("segment.in","r",stdin);
freopen("segment.out","w",stdout);
read(n),read(m);
build(1,1,n);
while(m--){
read(op);
if(op==1){
read(LL),read(RR),read(Val);
update(1,LL,RR,Val);
}
if(op==0){
read(LL),read(RR);
printf("%lld\n",query(1,LL,RR)%mod);
}
}
}