维护区间和+最大最小值就行了.
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<math.h>
using namespace std;
#define INF 99999999
#define ll long long
struct p{
int l,r;
ll lz,val,maxx,minn;
}tree[4*100010];
int read() {
char c=getchar();
int re=0,f=1;
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {re=re*10+c-'0';c=getchar();}
return re*f;
}
void buildtree(int i,int l,int r)
{
tree[i].l=l;tree[i].r =r;tree[i].minn=INF;
tree[i].lz=0;
if (l==r) {
tree[i].val=read();
tree[i].maxx=tree[i].minn=tree[i].val;
return;
}
int mid=(l+r)/2;
buildtree(i*2,l,mid);
buildtree(i*2+1,mid+1,r);
tree[i].maxx=max(tree[i*2].maxx,tree[i*2+1].maxx);
tree[i].minn=min(tree[i*2].minn,tree[i*2+1].minn);
tree[i].val=tree[i*2].val+tree[i*2+1].val;
}
void updata(int i,int l,int r,ll d)
{
if (tree[i].r==r&&tree[i].l==l)
{
tree[i].lz+=d;
tree[i].val+=(r-l+1)*d;
tree[i].maxx+=d;
tree[i].minn+=d;
return;
}
int mid=(tree[i].l+tree[i].r)/2;
if (tree[i].lz)
{
tree[i*2].lz+=tree[i].lz;
tree[i*2+1].lz+=tree[i].lz;
tree[i*2].maxx+=tree[i].lz;
tree[i*2+1].maxx+=tree[i].lz;
tree[i*2].minn+=tree[i].lz;
tree[i*2+1].minn+=tree[i].lz;
tree[i*2].val+=(mid-tree[i].l+1)*tree[i].lz;
tree[i*2+1].val+=(tree[i].r-mid)*tree[i].lz;
tree[i].lz=0;
}
if (r<=mid) {updata(i*2,l,r,d);}
if (l>mid) {updata(i*2+1,l,r,d);}
if (l<=mid&&r>mid){updata(i*2,l,mid,d);updata(i*2+1,mid+1,r,d);}
tree[i].val=tree[i*2].val+tree[i*2+1].val;
tree[i].maxx=max(tree[i*2].maxx,tree[i*2+1].maxx);
tree[i].minn=min(tree[i*2].minn,tree[i*2+1].minn);
}
ll find_val(int i,int l,int r)
{
if (tree[i].l==l&&tree[i].r==r)
{
return tree[i].val;
}
int mid=(tree[i].l+tree[i].r)/2;
if (tree[i].lz)
{
tree[i*2].lz+=tree[i].lz;
tree[i*2+1].lz+=tree[i].lz;
tree[i*2].maxx+=tree[i].lz;
tree[i*2+1].maxx+=tree[i].lz;
tree[i*2].minn+=tree[i].lz;
tree[i*2+1].minn+=tree[i].lz;
tree[i*2].val+=(mid-tree[i].l+1)*tree[i].lz;
tree[i*2+1].val+=(tree[i].r-mid)*tree[i].lz;
tree[i].lz=0;
}
if (r<=mid) return find_val(i*2,l,r);
if (l>mid) return find_val(i*2+1,l,r);
if (l<=mid&&r>mid) return find_val(i*2,l,mid)+find_val(i*2+1,mid+1,r);
}
void down(int i,int l,int r)
{
if (tree[i].l==l&&tree[i].r==r)
{
if(tree[i].maxx==tree[i].minn)
{
ll t=tree[i].maxx-floor((sqrt(tree[i].maxx*1.0)));
tree[i].lz-=t;
tree[i].val-=t*(r-l+1);
tree[i].maxx=tree[i].minn=tree[i].maxx-t;
return;
}
if(tree[i].maxx-tree[i].minn==1)
{
ll t1=floor((sqrt(tree[i].maxx*1.0)));
ll t2=floor((sqrt(tree[i].minn*1.0)));
ll t=tree[i].maxx-t1;
if (t1-t2==1)
{
tree[i].lz-=t;
tree[i].val-=t*(r-l+1);
tree[i].maxx=t1;
tree[i].minn=t2;
return;
}
}
}
int mid=(tree[i].l+tree[i].r)/2;
if (tree[i].lz)
{
tree[i*2].lz+=tree[i].lz;
tree[i*2+1].lz+=tree[i].lz;
tree[i*2].maxx+=tree[i].lz;
tree[i*2+1].maxx+=tree[i].lz;
tree[i*2].minn+=tree[i].lz;
tree[i*2+1].minn+=tree[i].lz;
tree[i*2].val+=(mid-tree[i].l+1)*tree[i].lz;
tree[i*2+1].val+=(tree[i].r-mid)*tree[i].lz;
tree[i].lz=0;
}
if (r<=mid) down(i*2,l,r);
if (l>mid) down(i*2+1,l,r);
if (l<=mid&&r>mid) {down(i*2,l,mid);down(i*2+1,mid+1,r);}
tree[i].val=tree[i*2].val+tree[i*2+1].val;
tree[i].maxx=max(tree[i*2].maxx,tree[i*2+1].maxx);
tree[i].minn=min(tree[i*2].minn,tree[i*2+1].minn);
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
int n,m;
n=read();
m=read();
buildtree(1,1,n);
for (int i=0;i<m;i++)
{
int opr,l,r;
opr=read();
l=read();
r=read();
if (opr==1){
int v;
v=read();
updata(1,l,r,v);
}
if (opr==2)
{
down(1,l,r);
}
if (opr==3)
{
printf("%I64d\n",find_val(1,l,r));
}
}
}
}