【题目大意】支持区间开根,区间加,区间求和。
【思路】维护区间的最大最小值。对于开根操作。如果极差==0,那么就相当于区间加一个负数。如果极差==1,考虑开根后的极差。如果开根后极差仍为1,就还是一个区间加。如果开根后极差为0,那么就是区间覆盖。代码如下。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#define lc (root<<1)
#define rc (root<<1|1)
#define mid (T[root].l+T[root].r>>1)
#define int long long
using namespace std;
const int maxn=1e5+5;
struct node{
int l,r,sum,maxx,minn,add,same;
}T[maxn<<2];
int n,m,op,x,y,v,t,a[maxn];
inline void read(int &x){
x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
}
void prin(int x){
if(x>9) prin(x/10);
putchar(x%10+48);
}
inline void pushup(int root){
T[root].sum=T[lc].sum+T[rc].sum;
T[root].maxx=max(T[lc].maxx,T[rc].maxx);
T[root].minn=min(T[lc].minn,T[rc].minn);
}
inline void pushdown(int root){
if(T[root].same){
T[lc].maxx=T[lc].minn=T[lc].same=T[root].same;
T[rc].maxx=T[rc].minn=T[rc].same=T[root].same;
T[lc].sum=(T[lc].r-T[lc].l+1)*T[root].same;
T[rc].sum=(T[rc].r-T[rc].l+1)*T[root].same;
T[lc].add=T[rc].add=0;
T[root].same=0;
}
if(T[root].add){
T[lc].add+=T[root].add;
T[rc].add+=T[root].add;
T[lc].sum+=T[root].add*(T[lc].r-T[lc].l+1);
T[rc].sum+=T[root].add*(T[rc].r-T[rc].l+1);
T[lc].maxx+=T[root].add,T[rc].maxx+=T[root].add;
T[lc].minn+=T[root].add,T[rc].minn+=T[root].add;
T[root].add=0;
}
}
void build(int root,int l,int r){
T[root].l=l,T[root].r=r,T[root].add=0,T[root].same=0;
if(l==r){
T[root].sum=a[l];
T[root].maxx=a[l];
T[root].minn=a[l];
return;
}
build(lc,l,mid),build(rc,mid+1,r);
pushup(root);
}
void uptadd(int root,int L,int R,int v){
if(L<=T[root].l&&R>=T[root].r){
T[root].add+=v;
T[root].sum+=(T[root].r-T[root].l+1)*v;
T[root].maxx+=v;
T[root].minn+=v;
return;
}
pushdown(root);
if(L<=mid) uptadd(lc,L,R,v);
if(R> mid) uptadd(rc,L,R,v);
pushup(root);
}
void uptsqrt(int root,int L,int R){
if(L<=T[root].l&&R>=T[root].r){
if(T[root].maxx==1) return;
if(T[root].l==T[root].r){
T[root].sum=T[root].maxx=T[root].minn=floor(sqrt(T[root].sum));
return;
}
if(T[root].maxx==T[root].minn){
int now=floor(sqrt(T[root].maxx));
T[root].add+=now-T[root].maxx;
T[root].sum=(T[root].r-T[root].l+1)*now;
T[root].maxx=T[root].minn=now;
return;
}
if(T[root].maxx-T[root].minn==1){
int Tmpb=T[root].maxx;int Tmps=T[root].minn;
int pos=T[root].sum-T[root].minn*(T[root].r-T[root].l+1);
T[root].maxx=floor(sqrt(T[root].maxx));
T[root].minn=floor(sqrt(T[root].minn));
if(T[root].maxx-T[root].minn==1){
T[root].add+=T[root].maxx-Tmpb;
T[root].sum=T[root].maxx*pos+T[root].minn*(T[root].r-T[root].l+1-pos);
}
else{
T[root].add=0,T[root].same=T[root].maxx;
T[root].sum=T[root].maxx*(T[root].r-T[root].l+1);
}
return;
}
}
pushdown(root);
if(L<=mid) uptsqrt(lc,L,R);
if(R> mid) uptsqrt(rc,L,R);
pushup(root);
}
int query(int root,int L,int R){
if(L<=T[root].l&&R>=T[root].r) return T[root].sum;
pushdown(root);
int ret=0;
if(L<=mid) ret+=query(lc,L,R);
if(R>mid) ret+=query(rc,L,R);
return ret;
}
signed main(){
read(t);
while(t--){
read(n),read(m);
for(int i=1;i<=n;++i) read(a[i]);
build(1,1,n);
while(m--){
read(op),read(x),read(y);
if(op==1) read(v),uptadd(1,x,y,v);
if(op==2) uptsqrt(1,x,y);
if(op==3) prin(query(1,x,y)),putchar('\n');
}
}
}