区间加操作正常做,考虑开根操作,维护区间最大最小值,如果区间的最大最小值开根后相同,则直接区间赋值,如果不同但最大值为最小值加1,则区间加上根号最小值减最小值,否则递归下去
考虑这个算法的复杂度,如果两个相邻的点导致包括这两个点的区间必须要从这里分成两边才能处理开根操作(即两个数开根后不同且大的那个不为小的那个+1),则称为一个分界点,一个分界点相当于把一次开根拆成两次,若不考虑区间加操作,由于序列初始值<=1e5则最多4次开根分界点就会消失,而区间加操作加的权值也<=1e5,所以一次区间加最多给两个点增加4次需要的操作,常数而已
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 100010
#define MAXM 1010
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
ll mx[MAXN<<2],mn[MAXN<<2],ch[MAXN<<2],ad[MAXN<<2];
ll s[MAXN<<2];
ll n,m;
inline void toch(ll x,ll y,ll z,ll v){
s[x]=(ll)(z-y+1)*v;
mx[x]=mn[x]=ch[x]=v;
ad[x]=0;
}
inline void toadd(ll x,ll y,ll z,ll v){
s[x]+=(ll)(z-y+1)*v;
mx[x]+=v;
mn[x]+=v;
ad[x]+=v;
}
inline void ud(ll x){
s[x]=s[x<<1]+s[x<<1|1];
mx[x]=max(mx[x<<1],mx[x<<1|1]);
mn[x]=min(mn[x<<1],mn[x<<1|1]);
}
inline void pd(ll x,ll y,ll z){
ll mid=y+z>>1;
if(ch[x]!=-1){
toch(x<<1,y,mid,ch[x]);
toch(x<<1|1,mid+1,z,ch[x]);
ch[x]=-1;
}
if(ad[x]){
toadd(x<<1,y,mid,ad[x]);
toadd(x<<1|1,mid+1,z,ad[x]);
ad[x]=0;
}
}
void build(ll x,ll y,ll z){
ch[x]=-1;
if(y==z){
scanf("%lld",&s[x]);
mx[x]=mn[x]=s[x];
return ;
}
ll mid=y+z>>1;
build(x<<1,y,mid);
build(x<<1|1,mid+1,z);
ud(x);
}
void add(ll x,ll y,ll z,ll l,ll r,ll av){
if(y==l&&z==r){
toadd(x,y,z,av);
return ;
}
pd(x,y,z);
ll mid=y+z>>1;
if(r<=mid){
add(x<<1,y,mid,l,r,av);
}else if(l>mid){
add(x<<1|1,mid+1,z,l,r,av);
}else{
add(x<<1,y,mid,l,mid,av);
add(x<<1|1,mid+1,z,mid+1,r,av);
}
ud(x);
}
void sq(ll x,ll y,ll z,ll l,ll r){
ll mid=y+z>>1;
if(y==l&&z==r){
if((ll)(sqrt(mn[x]))==(ll)(sqrt(mx[x]))){
toch(x,y,z,(ll)(sqrt(mn[x])));
return ;
}else if(mx[x]==mn[x]+1){
toadd(x,y,z,(ll)(sqrt(mn[x]))-mn[x]);
return ;
}
pd(x,y,z);
sq(x<<1,y,mid,l,mid);
sq(x<<1|1,mid+1,z,mid+1,r);
ud(x);
return ;
}
pd(x,y,z);
if(r<=mid){
sq(x<<1,y,mid,l,r);
}else if(l>mid){
sq(x<<1|1,mid+1,z,l,r);
}else{
sq(x<<1,y,mid,l,mid);
sq(x<<1|1,mid+1,z,mid+1,r);
}
ud(x);
}
ll ask(ll x,ll y,ll z,ll l,ll r){
if(y==l&&z==r){
return s[x];
}
pd(x,y,z);
ll mid=y+z>>1;
if(r<=mid){
return ask(x<<1,y,mid,l,r);
}else if(l>mid){
return ask(x<<1|1,mid+1,z,l,r);
}else{
return ask(x<<1,y,mid,l,mid)+ask(x<<1|1,mid+1,z,mid+1,r);
}
}
int main(){
/*
freopen("data.txt","r",stdin);
freopen("dui.txt","w",stdout);
//*/
ll i,x,y,z,o;
scanf("%lld%lld",&n,&m);
build(1,1,n);
while(m--){
scanf("%lld%lld%lld",&o,&x,&y);
if(o==1){
scanf("%lld",&z);
add(1,1,n,x,y,z);
}
if(o==2){
sq(1,1,n,x,y);
}
if(o==3){
printf("%lld\n",ask(1,1,n,x,y));
}
}
return 0;
}
/*
5 5
2 5 4 2 1
1 1 5 4
3 3 3
1 3 3 4
3 3 3
2 2 5
*/