思路

我们没有办法直接对区间进行开方然后下传,所以pushdown就没必要写了。
对于每个数,开方6次之后达到势能上限,其结果必然为0或者1。那么对于整个区间,
可以记录开方次数(取区间内开方次数最少的那个值)是否达到6就可以了,
或者只要一个区间全为0或1的话,也可以直接返回。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int maxn=2e5+7;

int n,m,op,l,r;
int tr[maxn<<2],cnt[maxn<<2];

void build(int node,int l,int r){
    if(l==r){
        cin>>tr[node];
        return;
    }
    int mid=l+r>>1;
    build(node<<1,l,mid);
    build(node<<1|1,mid+1,r);
    tr[node]=tr[node<<1]+tr[node<<1|1];
    cnt[node]=cnt[node<<1]+cnt[node<<1|1];
}

int query(int node,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
        return tr[node];
    }
    int mid=l+r>>1,res=0;
    if(ql<=mid) res+=query(node<<1,l,mid,ql,qr);
    if(qr>mid) res+=query(node<<1|1,mid+1,r,ql,qr);
    return res;
}

void update(int node,int l,int r,int ql,int qr){
    if(cnt[node]>5) return;
    if(l==r){
        tr[node]=sqrt(tr[node]);
        cnt[node]++;
        return;
    }
    int mid=l+r>>1;
    if(ql<=mid) update(node<<1,l,mid,ql,qr);
    if(qr>mid) update(node<<1|1,mid+1,r,ql,qr);
    tr[node]=tr[node<<1]+tr[node<<1|1];
    cnt[node]=min(cnt[node<<1],cnt[node<<1|1]);
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    build(1,1,n);
    for(int i=1;i<=m;i++){
        cin>>op>>l>>r;
        if(op==1){
            update(1,1,n,l,r);
        }else{
            cout<<query(1,1,n,l,r)<<endl;
        }
    }
    return 0;
}