P4458题解
Raymondzll · · 题解
P4458 链上二次求和
前言
尽量做到一气呵成,会 sigma 的小学生都能看懂,因为真的就是线段树和推式子。
解题思路
记原链表为
我们要维护
当对
对于
对于
最后一点,lazy 数组可以用三个数 la,lb,lc 三个数表示,代表 val[id] 需要加上
相信没有什么疑问了吧。
细节
-
可能出现
l>r 。 -
除以
2 和6 就算出2 和6 在\pmod{1000000007} 下的逆元就行。 -
注意负数和各种奇怪的溢出。
-
不要写着写着忘了式子,坚定信念,也就一百多行。
代码部分
#include <bits/stdc++.h>
using namespace std;
void file(string str){
freopen((str+".in").c_str(),"r",stdin);
freopen((str+".out").c_str(),"w",stdout);
}
const int MAXN=200010;
const int mod=1e9+7,inv2=5e8+4,inv6=inv2/3;
int n,m,init[MAXN],s[MAXN],ss[MAXN];
int val[MAXN<<2],laa[MAXN<<2],lab[MAXN<<2],lac[MAXN<<2];
inline int ad(int a,int b){return (a+b)%mod;}
inline int add(int a,int b,int c=0,int d=0){return ad(ad(a,b),ad(c,d));}
inline int mu(int a,int b){return 1ll*a*b%mod;}
inline int mul(int a,int b,int c=1,int d=1){return mu(mu(a,b),mu(c,d));}
int p1sum(int a){return mul(a,a+1,inv2);}
int p2sum(int a){return mul(a,a+1,2*a+1,inv6);}
int p1sum(int a,int b){return p1sum(b)-p1sum(a-1);}
int p2sum(int a,int b){return p2sum(b)-p2sum(a-1);}
void ___(int &a){a%=mod;if(a<0)a+=mod;}
void pushup(int id){val[id]=add(val[id<<1],val[id<<1|1]);}
void tag(int id,int l,int r,int la,int lb,int lc){
val[id]=add(val[id],mul(la,p2sum(l,r)),mul(lb,p1sum(l,r)),mul(lc,r-l+1));
___(val[id]);laa[id]=add(laa[id],la);lab[id]=add(lab[id],lb);lac[id]=add(lac[id],lc);
}
void pushdown(int id,int l,int r){
if(laa[id]||lab[id]||lac[id]){
int mid=(l+r)>>1;
tag(id<<1,l,mid,laa[id],lab[id],lac[id]);
tag(id<<1|1,mid+1,r,laa[id],lab[id],lac[id]);
laa[id]=lab[id]=lac[id]=0;
}
}
void update(int id,int l,int r,int ql,int qr,int la,int lb,int lc){
if(r<ql||l>qr)return;
if(l>=ql&&r<=qr){tag(id,l,r,la,lb,lc);return;}
int mid=(l+r)>>1;pushdown(id,l,r);
update(id<<1,l,mid,ql,qr,la,lb,lc);
update(id<<1|1,mid+1,r,ql,qr,la,lb,lc);
pushup(id);
}
int query(int id,int l,int r,int ql,int qr){
if(r<ql||l>qr)return 0;
if(l>=ql&&r<=qr)return val[id];
int mid=(l+r)>>1;pushdown(id,l,r);
return add(query(id<<1,l,mid,ql,qr),query(id<<1|1,mid+1,r,ql,qr));
}
void build(int id,int l,int r){
if(l==r){val[id]=ss[l];return;}
int mid=(l+r)>>1;
build(id<<1,l,mid);build(id<<1|1,mid+1,r);pushup(id);
}
void UPDATE(int l,int r,int d){
int inv2_d=mul(inv2,d);
update(1,1,n,l,r,inv2_d,mul((mod+3-2*l),inv2_d),mul(l-1,l-2,inv2_d));
int tmp1=mul(p1sum(r-l+1),d),tmp2=mul(r-l+1,d);
if(r<n)update(1,1,n,r+1,n,0,tmp2,tmp1-mul(tmp2,r));
}
int QUERY(int l,int r){
int res=mul(r-l+1,query(1,1,n,n,n));
res-=query(1,1,n,l-1,r-1);res-=query(1,1,n,n-r,n-l);
___(res);return res;
}
void initt(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&init[i]);
s[i]=add(s[i-1],init[i]);ss[i]=add(ss[i-1],s[i]);
}
build(1,1,n);
}
int main(){
initt();
for(int i=1;i<=m;i++){
int op,a,b,c;
scanf("%d%d%d",&op,&a,&b);
if(op==1){scanf("%d",&c);if(a>b)swap(a,b);UPDATE(a,b,c);}
else printf("%d\n",QUERY(a,b));
}
return 0;
}