版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/88257200
洛谷传送门
BZOJ传送门
解析:
直接来看我们要求的式子,设 是点权的前缀和, 是 的前缀和
一个询问
表示要求的是
实际上就是询问 的区间和。
我们考虑一个修改 会对数组 产生什么影响。
我们知道,前缀和的逆运算是差分,所以实际上我们是在 的二阶差分数组上面修改,而一个 次的修改,做两次前缀和,影响是。。。二次函数。
手推一下可以得到,对于 ,影响是:
而对于后面的数 ,由于差分的影响达不到这里,所以这里的变换是一次的,为:
其中 。
线段树维护区间加一个与下标有关的二次函数就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int mod=1e9+7,inv2=(mod+1)/2;
inline int add(cs int &a,cs int &b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(cs int &a,cs int &b){return a<b?a-b+mod:a-b;}
inline int mul(cs int &a,cs int &b){return (ll)a*b%mod;}
cs int N=200005;
int n,m;
int a[N<<2],b[N<<2],c[N<<2];
int sum[N<<2];
int d1[N],d2[N];
inline void pushup(cs int &k){sum[k]=add(sum[k<<1],sum[k<<1|1]);}
inline void pushadd(cs int &k,cs int &l,cs int &r,cs int &da,cs int &db,cs int &dc){
a[k]=add(a[k],da),b[k]=add(b[k],db),c[k]=add(c[k],dc);
sum[k]=add(sum[k],add(add(mul(da,dec(d2[r],d2[l-1])),mul(db,dec(d1[r],d1[l-1]))),mul(r-l+1,dc)));
}
inline void pushdown(cs int &k,cs int &l,cs int &r){
if(a[k]||b[k]||c[k]){
int mid=(l+r)>>1;
pushadd(k<<1,l,mid,a[k],b[k],c[k]);
pushadd(k<<1|1,mid+1,r,a[k],b[k],c[k]);
a[k]=b[k]=c[k]=0;
}
}
int ss[N];
inline void build(int k,cs int &l,cs int &r){
if(l==r){
sum[k]=ss[l];
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
inline void modify(int k,cs int &l,cs int &r,cs int &ql,cs int &qr,cs int &a,cs int &b,cs int &c){
if(ql<=l&&r<=qr)return pushadd(k,l,r,a,b,c);
int mid=(l+r)>>1;
pushdown(k,l,r);
if(ql<=mid)modify(k<<1,l,mid,ql,qr,a,b,c);
if(mid<qr)modify(k<<1|1,mid+1,r,ql,qr,a,b,c);
pushup(k);
}
inline int query(int k,cs int &l,cs int &r,cs int &ql,cs int &qr){
if(ql<=l&&r<=qr)return sum[k];
pushdown(k,l,r);
int mid=(l+r)>>1;
if(qr<=mid)return query(k<<1,l,mid,ql,qr);
if(mid<ql)return query(k<<1|1,mid+1,r,ql,qr);
return add(query(k<<1,l,mid,ql,qr),query(k<<1|1,mid+1,r,ql,qr));
}
signed main(){
n=getint(),m=getint();
for(int re i=1;i<=n;++i)ss[i]=add(getint(),ss[i-1]);
for(int re i=1;i<=n;++i)ss[i]=add(ss[i],ss[i-1]);
for(int re i=1;i<=n;++i)d1[i]=add(d1[i-1],i),d2[i]=add(d2[i-1],mul(i,i));
build(1,0,n);
int l,r,v,a,b,c,len;
while(m--){
switch(getint()){
case 1:{
l=getint(),r=getint();
if(l>r)swap(l,r);
v=getint();
a=inv2;
b=mul(dec(3,add(l,l)),inv2);
c=mul(mul(l-1,l-2),inv2);
modify(1,0,n,l,r,mul(a,v),mul(b,v),mul(c,v));
if(r==n)break;
len=r-l+1;
modify(1,0,n,r+1,n,0,mul(r-l+1,v),mul(v,dec(mul(inv2,mul(len,len+1)),mul(len,r))));
break;
}
case 2:{
l=getint(),r=getint();
cout<<dec(mul(query(1,0,n,n,n),r-l+1),add(query(1,0,n,l-1,r-1),query(1,0,n,n-r,n-l)))<<"\n";
break;
}
}
}
return 0;
}