【题意】给了一个序列,3个操作,1是给区间[l,r]加上一个数,2是给区间[l,r]里每个数开平方,3是查询[l,r]的和。

【解题方法】

其实这道题线段树就完全可以维护了,平衡树不会,线段树节点里面保存了两个标记,一个是add(区间加),一个是区间里面元素是否相同,接下来很重要的主要是pushdown的写法了,这里一定要先考虑issame标记,然后考虑add,这个顺序一定不能反。具体细节见代码了。

【AC 代码】

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=1e5+10;
struct node{
    int l,r;
    LL sum;
    LL add,issame;
}Tree[maxn<<2];
void pushup(int rt){
    if(Tree[rt*2].issame&&Tree[rt*2+1].issame&&Tree[rt*2].issame==Tree[rt*2+1].issame){
        Tree[rt].issame=Tree[rt*2].issame;
    }else{
        Tree[rt].issame=0;
    }
    Tree[rt].sum=Tree[rt*2].sum+Tree[rt*2+1].sum;
}
void pushdown(int rt){
    int m=(Tree[rt].r+Tree[rt].l)/2;
    if(Tree[rt].issame){
        Tree[rt*2].issame=Tree[rt].issame;
        Tree[rt*2+1].issame=Tree[rt].issame;
        Tree[rt*2].sum=(m-Tree[rt].l+1)*Tree[rt].issame;
        Tree[rt*2+1].sum=(Tree[rt].r-m)*(Tree[rt].issame);
    }else{
        Tree[rt*2].add+=Tree[rt].add;
        Tree[rt*2+1].add+=Tree[rt].add;
        Tree[rt*2].sum+=Tree[rt].add*(m-Tree[rt].l+1);
        Tree[rt*2+1].sum+=Tree[rt].add*(Tree[rt].r-m);
        Tree[rt].add=0;
        if(Tree[rt*2].issame){
            Tree[rt*2].issame+=Tree[rt*2].add;
            Tree[rt*2].add=0;
        }
        if(Tree[rt*2+1].issame){
            Tree[rt*2+1].issame+=Tree[rt*2+1].add;
            Tree[rt*2+1].add=0;
        }
    }
}
int A[maxn];
void Build(int l,int r,int rt){
    Tree[rt].l=l,Tree[rt].r=r;
    Tree[rt].add=0;
    if(l==r){
        Tree[rt].sum=A[l];
        Tree[rt].issame=A[l];
        return ;
    }
    int mid=(l+r)/2;
    Build(l,mid,rt*2);
    Build(mid+1,r,rt*2+1);
    pushup(rt);
}
void update1(int L,int R,LL v,int rt){
    if(L==Tree[rt].l&&Tree[rt].r==R){
        Tree[rt].sum+=v*(Tree[rt].r-Tree[rt].l+1);
        if(Tree[rt].issame){
            Tree[rt].issame+=v;
        }else{
            Tree[rt].add+=v;
        }
        return ;
    }
    pushdown(rt);
    int mid=(Tree[rt].l+Tree[rt].r)/2;
    if(R<=mid) update1(L,R,v,rt*2);
    else if(L>mid) update1(L,R,v,rt*2+1);
    else{
        update1(L,mid,v,rt*2);
        update1(mid+1,R,v,rt*2+1);
    }
    pushup(rt);
}
void update2(int L,int R,int rt){
    if(L==Tree[rt].l&&R==Tree[rt].r&&Tree[rt].issame){
        Tree[rt].issame=sqrt(Tree[rt].issame);
        Tree[rt].sum=Tree[rt].issame*(Tree[rt].r-Tree[rt].l+1);
        return ;
    }
    pushdown(rt);
    int mid=(Tree[rt].l+Tree[rt].r)/2;
    if(R<=mid) update2(L,R,rt*2);
    else if(L>mid) update2(L,R,rt*2+1);
    else{
        update2(L,mid,rt*2);
        update2(mid+1,R,rt*2+1);
    }
    pushup(rt);
}
LL queryans(int L,int R,int rt){
    if(L==Tree[rt].l&&R==Tree[rt].r){
        return Tree[rt].sum;
    }
    pushdown(rt);
    int mid=(Tree[rt].l+Tree[rt].r)/2;
    if(R<=mid) return queryans(L,R,rt*2);
    else if(L>mid) return queryans(L,R,rt*2+1);
    else{
        return queryans(L,mid,rt*2)+queryans(mid+1,R,rt*2+1);
    }
}
int main(){
    int T,n,m;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++){
            scanf("%d",&A[i]);
        }
        Build(1,n,1);
        //puts("success");
        int op,l,r;LL x;
        for(int i=1; i<=m; i++){
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d%lld",&l,&r,&x);
                update1(l,r,x,1);
            }else if(op==2){
                scanf("%d%d",&l,&r);
                update2(l,r,1);
            }
            else{
                scanf("%d%d",&l,&r);
                LL ans=queryans(l,r,1);
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}