思路

要维护区间和以及平方和两个线段树,同时支持加法和乘法操作。
前面基本套模板就行了,那么我们重点是pushdown怎么写。
(这个板子是参照oi-wiki先打出lazy的pushdown的,已经能支持加法维护区间和了)
我们可以用上述式子Pushdown区间平方和。
考虑乘法:
一开始我们建立cheng记录结点需要pushdown的乘数,在往下传递的过程中

这样两个线段树的更新操作就完成了。

代码

#include<bits/stdc++.h>
#define int ll
typedef long long ll; 
using namespace std;
const int maxn=10005;
int n,m,opt,l,r,x;
int num[maxn],tree[maxn*4],fang[maxn*4];
int lazy[maxn*4],cheng[maxn*4];

inline void read(int &data){
    int x=0,flag=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') flag=flag*-1;
        ch=getchar(); 
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    data=x*flag;
} 

void pushdown(int node,int start,int end){
    int mid=start+end>>1;
    lazy[node<<1]*=cheng[node];
    lazy[node<<1|1]*=cheng[node];
    cheng[node<<1]*=cheng[node];
    cheng[node<<1|1]*=cheng[node];
    tree[node<<1]*=cheng[node];
    tree[node<<1|1]*=cheng[node];
    fang[node<<1]*=cheng[node]*cheng[node];
    fang[node<<1|1]*=cheng[node]*cheng[node];
    cheng[node]=1;
    if(lazy[node]){
        lazy[node<<1]+=lazy[node];
        lazy[node<<1|1]+=lazy[node]; 
        fang[node<<1]+=2*lazy[node]*tree[node<<1]+(mid-start+1)*lazy[node]*lazy[node];
        fang[node<<1|1]+=2*lazy[node]*tree[node<<1|1]+(end-mid)*lazy[node]*lazy[node];
        tree[node<<1]+=lazy[node]*(mid-start+1);
        tree[node<<1|1]+=lazy[node]*(end-mid);
        lazy[node]=0;
    }
}

void pushup(int node){
    tree[node]=tree[node<<1]+tree[node<<1|1];
    fang[node]=fang[node<<1]+fang[node<<1|1];
}

void build(int node,int start,int end){
    lazy[node]=0;cheng[node]=1;
    if(start==end){
        tree[node]=num[start];
        fang[node]=tree[node]*tree[node];
        return;
    }
    int mid=start+end>>1;
    build(node<<1,start,mid);
    build(node<<1|1,mid+1,end);
    pushup(node);
}

int query1(int node,int start,int end,int l,int r){
    if(l<=start&&end<=r) return tree[node];
    int mid=start+end>>1;
    pushdown(node,start,end);
    int res=0;
    if(l<=mid) res+=query1(node<<1,start,mid,l,r);
    if(r>mid) res+=query1(node<<1|1,mid+1,end,l,r);
    return res; 
}


int query2(int node,int start,int end,int l,int r){
    if(l<=start&&end<=r) return fang[node];
    int mid=start+end>>1;
    pushdown(node,start,end);
    int res=0;
    if(l<=mid) res+=query2(node<<1,start,mid,l,r);
    if(r>mid) res+=query2(node<<1|1,mid+1,end,l,r);
    return res; 
}

void add(int node,int start,int end,int l,int r,int val){
    if(l<=start&&end<=r){
        lazy[node]+=val;
        fang[node]+=2*val*tree[node]+(end-start+1)*val*val;
        tree[node]+=(end-start+1)*val;
        return;
    }
    int mid=start+end>>1;
    pushdown(node,start,end);
    if(l<=mid) add(node<<1,start,mid,l,r,val);
    if(r>mid) add(node<<1|1,mid+1,end,l,r,val);
    pushup(node);
}

void multi(int node,int start,int end,int l,int r,int val){
    if(l<=start&&end<=r){
        lazy[node]*=val;
        cheng[node]*=val;
        tree[node]*=val;
        fang[node]*=val*val;
        return;
    }
    int mid=start+end>>1;
    pushdown(node,start,end);
    if(l<=mid) multi(node<<1,start,mid,l,r,val);
    if(r>mid) multi(node<<1|1,mid+1,end,l,r,val);
    pushup(node);
}

signed main(){
    read(n);read(m);
    for(int i=1;i<=n;i++)    read(num[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        read(opt);
        if(opt==1){
            read(l);read(r);
            printf("%lld\n",query1(1,1,n,l,r));
        }
        if(opt==2){
            read(l);read(r);
            printf("%lld\n",query2(1,1,n,l,r));
        }
        if(opt==3){
            read(l);read(r);read(x);
            multi(1,1,n,l,r,x);
        }
        if(opt==4){
            read(l);read(r);read(x);
            add(1,1,n,l,r,x);            
        }
    }
    return 0;
}