题意:
给一个序列,有俩种操作,一种是求区间和,一种是将区间每个数开根号后向下取整(QQ浏览器翻译成了四舍五入,坑了我很久)。

思路:
因为是对区间内的每个数开根号,没有办法用延迟更新,但是取根号在6,7次就会到1,所以如果父节点的权值等于r-l+1就不用往下跟新了,因为这个区间里每个数都是1,这样修改的复杂度就很低了总复杂度是

题目说的是对x到y进行操作,并没有说明x、y的大小关系,所以x可能会大于y,需要交换x、y

Code:

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
inline ll read() {
    ll s = 0, w = 1;
    char ch = getchar();
    while (ch < 48 || ch > 57) {
        if (ch == '-') w = -1;
        ch = getchar();
    }
    while (ch >= 48 && ch <= 57)
        s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}
ll tree[maxn<<2];
inline void build(int l,int r,int rt) {
    if(l==r) {
        tree[rt]=read();
        return;
    }
    int mid=l+r>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
inline void update(int x,int y,int l,int r,int rt) {
    if(tree[rt]==r-l+1) return;
    if(l==r) {
        tree[rt]=sqrt(tree[rt]);
        return;
    }
    int mid=l+r>>1;
    if(x<=mid) update(x,y,l,mid,rt<<1);
    if(y>mid) update(x,y,mid+1,r,rt<<1|1);
    tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
inline ll query(int x,int y,int l,int r,int rt) {
    if(x<=l&&r<=y) return tree[rt];
    int mid=l+r>>1;
    ll ans=0;
    if(x<=mid) ans=query(x,y,l,mid,rt<<1);
    if(y>mid) ans+=query(x,y,mid+1,r,rt<<1|1);
    return ans;
}
int main() {
    int n,m,t,x,y,cas=0;
    while(~scanf("%d",&n)) {
        build(1,n,1);
        m=read();
        printf("Case #%d:\n",++cas);
        while(m--) {
            t=read(),x=read(),y=read();
            if(x>y) swap(x,y);
            if(t) printf("%lld\n",query(x,y,1,n,1));
            else update(x,y,1,n,1);
        }
        puts("");
    }
    return 0;
}