对于一个区间内开平方的复杂度是相当大的,但是只有当一个区间内有一个数 >=2 时才有资格开平方,所以添加一个数组来维护整个块是否需要开平方
const int N=5e4+5;
int i,j,k;
int n,m,t;
int a[N];
int L[N],R[N];
int bel[N],block,num,sum[N],all[N];
void build()
{
block=sqrt(n);
num=n/block; if(n%block) num++;
for(int i=1;i<=num;i++){
int l=(i-1)*block+1;
int r=min(i*block,n);
L[i]=l,R[i]=r;
sum[i]=0,all[i]=0;
for(int j=l;j<=r;j++){
bel[j]=i,sum[i]+=a[j];
if(a[j]>1) all[i]=1;
}
}
}
void renew(int fa)
{
int l=L[fa],r=R[fa];
sum[fa]=all[fa]=0;
for(int i=l;i<=r;i++) sum[fa]+=a[i];
for(int i=l;i<=r;i++){
if(a[i]>1){ all[fa]=1; return ; }
}
}
void update(int l,int r)
{
int st=bel[l],en=bel[r];
if(st==en){
if(all[st]==0) return ;
for(int i=l;i<=r;i++) a[i]=sqrt(a[i]);
renew(st);
} else{
for(int i=l;i<=R[st];i++) a[i]=sqrt(a[i]);
renew(st);
for(int i=L[en];i<=r;i++) a[i]=sqrt(a[i]);
renew(en);
for(int i=st+1;i<=en-1;i++){
if(all[i]==0) continue;
for(int j=L[i];j<=R[i];j++) a[j]=sqrt(a[j]);
renew(i);
}
}
}
int query(int l,int r)
{
int ans=0;
int st=bel[l],en=bel[r];
if(st==en){
for(int i=l;i<=r;i++) ans+=a[i];
} else{
for(int i=l;i<=R[st];i++) ans+=a[i];
for(int i=L[en];i<=r;i++) ans+=a[i];
for(int i=st+1;i<=en-1;i++) ans+=sum[i];
}
return ans;
}
int main()
{
//IOS;
while(~sd(n)){
for(int i=1;i<=n;i++) sd(a[i]);
build();
while(n--){
int opt=read(),x=read(),y=read(),w=read();
if(opt) pd(query(x,y));
else update(x,y);
}
}
//PAUSE;
return 0;
}