链上二次求和
正在肝的一道黑题……
首先处理那个奇怪的询问操作。我们可以对于那个奇怪的东西进行暴力推式:
用前缀和搞一下就是
分离一下
emmmm,发现它似乎仍然具有前缀和的性质,考虑搞个前缀和的前缀和(
展开:
于是那个奇怪的询问就变成了单纯的对于su数组的区间和查询。
按照思考此类问题的惯常方法,考虑假如我们给
同样可以得出,假如
开心地发现
发现前半部分是个定值,相当于是普通区间加;后半部分相当于是区间加
所以
发现
最后我们发现,上面推出来的柿子为真正增量的两倍。取模意义下除法灰常麻烦,于是我的做法是线段树中维护的是增量的两倍,询问时乘上2的逆元就可以了。
最后说明一点,由于这道题对取模的要求苛刻得有些丧心病狂,一定要认真取模。然后本蒟蒻代码能力极差,码风自然氢气,见谅。
#include<cstdio>
//#define zczc
#define int long long
const int N=200010;
const int yy=500000004;
const int mod=1000000007;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
int m,n,a[N];
#define lc (wh<<1)
#define rc (wh<<1|1)
#define mid (t[wh].l+t[wh].r>>1)
//直接区间加的那棵树
namespace ta{
struct node{
int l,r,data,lazy;
}t[N<<2];
inline void pushup(int wh){
t[wh].data=(t[lc].data+t[rc].data)%mod;
return;
}
inline void pushnow(int wh,int val){
t[wh].lazy+=val;
t[wh].lazy%=mod;
t[wh].data+=val*(t[wh].r-t[wh].l+1)%mod;
t[wh].data%=mod;
return;
}
inline void pushdown(int wh){
if(t[wh].lazy){
pushnow(lc,t[wh].lazy);
pushnow(rc,t[wh].lazy);
t[wh].lazy=0;
}
return;
}
inline void build(int wh,int l,int r){
t[wh].l=l,t[wh].r=r;
if(l==r){
t[wh].data=a[l];
return;
}
build(lc,l,mid);
build(rc,mid+1,r);
pushup(wh);
return;
}
inline void change(int wh,int wl,int wr,int val){
if(wl<=t[wh].l&&t[wh].r<=wr){
pushnow(wh,val);
return;
}
pushdown(wh);
if(wl<=mid)change(lc,wl,wr,val);
if(wr>mid)change(rc,wl,wr,val);
pushup(wh);
return;
}
inline int work(int wh,int wl,int wr){
if(wl<=t[wh].l&&t[wh].r<=wr){
return t[wh].data;
}
pushdown(wh);
int an=0;
if(wl<=mid)an+=work(lc,wl,wr);
if(wr>mid)an+=work(rc,wl,wr);
return an%mod;
}
inline int ask(int wh,int pl){
if(t[wh].l==t[wh].r)return t[wh].data;
pushdown(wh);
if(pl<=mid)return ask(lc,pl);
else return ask(rc,pl);
}
}
//区间加下标的那棵树
namespace tb{
struct node{
int l,r,data,lazy;
}t[N<<2];
inline void pushup(int wh){
t[wh].data=(t[lc].data+t[rc].data)%mod;
return;
}
inline int s(int l,int r){
return (l+r)*(r-l+1)/2%mod;
}
inline void pushnow(int wh,int val){
t[wh].lazy+=val;t[wh].lazy%=mod;
t[wh].data+=val*s(t[wh].l,t[wh].r)%mod;
t[wh].data%=mod;
return;
}
inline void pushdown(int wh){
if(t[wh].lazy){
pushnow(lc,t[wh].lazy);
pushnow(rc,t[wh].lazy);
t[wh].lazy=0;
}
return;
}
inline void build(int wh,int l,int r){
t[wh].l=l,t[wh].r=r;
if(l==r)return;
build(lc,l,mid);
build(rc,mid+1,r);
pushup(wh);
return;
}
inline void change(int wh,int wl,int wr,int val){
if(wl<=t[wh].l&&t[wh].r<=wr){
pushnow(wh,val);
return;
}
pushdown(wh);
if(wl<=mid)change(lc,wl,wr,val);
if(wr>mid)change(rc,wl,wr,val);
pushup(wh);
return;
}
inline int work(int wh,int wl,int wr){
if(wl<=t[wh].l&&t[wh].r<=wr){
return t[wh].data;
}
pushdown(wh);
int an=0;
if(wl<=mid)an+=work(lc,wl,wr);
if(wr>mid)an+=work(rc,wl,wr);
return an%mod;
}
inline int ask(int wh,int pl){
if(t[wh].l==t[wh].r)return t[wh].data;
pushdown(wh);
if(pl<=mid)return ask(lc,pl);
else return ask(rc,pl);
}
}
//区间加下标平方的那棵树
namespace tc{
struct node{
int l,r,data,lazy;
}t[N<<2];
inline void pushup(int wh){
t[wh].data=(t[lc].data+t[rc].data)%mod;
return;
}
inline int s(int wh){
return wh*(wh+1)/2*(2*wh+1)/3%mod;
}
inline void pushnow(int wh,int val){
t[wh].lazy+=val;t[wh].lazy%=mod;
t[wh].data+=val*(s(t[wh].r)-s(t[wh].l-1)+mod)%mod;
t[wh].data%=mod;
return;
}
inline void pushdown(int wh){
if(t[wh].lazy){
pushnow(lc,t[wh].lazy);
pushnow(rc,t[wh].lazy);
t[wh].lazy=0;
}
return;
}
inline void build(int wh,int l,int r){
t[wh].l=l,t[wh].r=r;
if(l==r)return;
build(lc,l,mid);
build(rc,mid+1,r);
pushup(wh);
return;
}
inline void change(int wh,int wl,int wr,int val){
if(wl<=t[wh].l&&t[wh].r<=wr){
pushnow(wh,val);
return;
}
pushdown(wh);
if(wl<=mid)change(lc,wl,wr,val);
if(wr>mid)change(rc,wl,wr,val);
pushup(wh);
return;
}
inline int work(int wh,int wl,int wr){
if(wl<=t[wh].l&&t[wh].r<=wr){
return t[wh].data;
}
pushdown(wh);
int an=0;
if(wl<=mid)an+=work(lc,wl,wr);
if(wr>mid)an+=work(rc,wl,wr);
return an%mod;
}
inline int ask(int wh,int pl){
if(t[wh].l==t[wh].r)return t[wh].data;
pushdown(wh);
if(pl<=mid)return ask(lc,pl);
else return ask(rc,pl);
}
}
#undef lc
#undef rc
#undef mid
inline int solve(int l,int r){
if(l==r){
return (ta::ask(1,l)+(tb::ask(1,l)+tc::ask(1,l))%mod*yy%mod)%mod;
}
else{
return (ta::work(1,l,r)+(tb::work(1,l,r)+tc::work(1,l,r))%mod*yy%mod)%mod;
}
}
signed main(){
#ifdef zczc
freopen("a.in","r",stdin);
#endif
read(m);read(n);
for(int i=1;i<=m;i++){read(a[i]);a[i]+=a[i-1];a[i]%=mod;}
for(int i=1;i<=m;i++)a[i]+=a[i-1],a[i]%=mod;
//for(int i=1;i<=m;i++)printf("%d ",a[i]);
ta::build(1,0,m);
tb::build(1,0,m);
tc::build(1,0,m);
int op,l,r,val;
while(n--){
read(op);read(l);read(r);
if(l>r){int s1=l;l=r;r=s1;}
if(op==2){
int an=solve(m,m)*(r-l+1)-solve(l-1,r-1)-solve(m-r,m-l);
printf("%lld\n",(an%mod+mod)%mod);
}
else{
read(val);
if(r<m){
int len=r-l+1;
ta::change(1,r+1,m,((val*len%mod*(len+1)%mod*yy%mod-val*len%mod*r%mod)%mod+mod)%mod);
tb::change(1,r+1,m,2*val*len%mod);
}
ta::change(1,l,r,(l-1)*(l-2)%mod*val%mod*yy%mod);
tb::change(1,l,r,val*(3-2*l)%mod);
tc::change(1,l,r,val);
}
}
return 0;
}
一如既往,万事胜意
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具