回顾一下线段树求幂次方和的操作
#include
using namespace std;
const int N = 1e4+100;
typedef long long ll;
struct segtree{
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
ll sum[N<<2],add[N<<2],mul[N<<2],sum2[N<<2];
void cal(int id,ll c,ll d,ll len){
sum2[id]=(sum2[id]*d*d+2ll*sum[id]*c*d+c*c*len);
sum[id]=sum[id]*d+c*len;
mul[id]*=d;
add[id]=add[id]*d+c;
}
void pushdown(int id,int l,int r){
int mid = l+r>>1;
if(add[id]||mul[id]!=1){
cal(id<<1,add[id],mul[id],mid-l+1);
cal(id<<1|1,add[id],mul[id],r-mid);
add[id]=0,mul[id]=1;
}
}
void pushup(int id){
sum[id]=sum[id<<1]+sum[id<<1|1];
sum2[id]=sum2[id<<1]+sum2[id<<1|1];
}
void build(int id,int l,int r){
mul[id]=1;add[id]=0;
if(l==r){
scanf("%lld",&sum[id]);
sum2[id]=sum[id]*sum[id];
return;
}
int mid = l+r>>1;
build(lson);build(rson);
pushup(id);
}
ll query(int id,int l,int r,int L,int R,int op){
if(L<=l&&R>=r){
return op?sum[id]:sum2[id];
}
pushdown(id,l,r);
int mid = l+r>>1;
ll ans = 0;
if(L<=mid) ans+=query(lson,L,R,op);
if(R>mid) ans+=query(rson,L,R,op);
return ans;
}
void update(int id,int l,int r,int L,int R,ll c,ll d){
if(L<=l&&R>=r){
cal(id,c,d,r-l+1);
return;
}
int mid = l+r>>1;
pushdown(id,l,r);
if(L<=mid) update(lson,L,R,c,d);
if(R>mid) update(rson,L,R,c,d);
pushup(id);
}
}s;
int main(){
int n,m;
scanf("%d%d",&n,&m);
s.build(1,1,n);
for(int i = 1; i <= m; i++){
int op,l,r;ll x;
scanf("%d%d%d",&op,&l,&r);
if(op<=2){
printf("%lld\n",s.query(1,1,n,l,r,op%2));
}else{
scanf("%lld",&x);
if(op==3) s.update(1,1,n,l,r,0,x);
else s.update(1,1,n,l,r,x,1);
}
}
return 0;
}