线段树题,打个标记即可,因为如果那个位置的值被降到了1/0,再怎么sqrt它也不会变。如果一个节点的两个子树已经全部被打了标记,那么就不用再更新了。
这份代码因为一开始打错了疯狂T,加了各种鬼畜优化。。。(貌似这的跑的能快一点点)
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cctype>
#include <cstring>
const int N=100005;
typedef long long ll;
struct Segtree {
ll l,r,sum;
bool flag;
} t[N<<2];
ll a[N],n,m;
ll rd() {
ll x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x;
}
void pushup(int cur) {
cur[t].sum=(cur<<1)[t].sum+(cur<<1|1)[t].sum;
cur[t].flag=(cur<<1)[t].flag&(cur<<1|1)[t].flag;
}
void build(int cur,int l,int r) {
cur[t].l=l;
cur[t].r=r;
if(l==r) {
cur[t].sum=rd();
if(cur[t].sum==1||cur[t].sum==0) cur[t].flag=1;
return;
}
int mid=l+r>>1;
build(cur<<1,l,mid);
build(cur<<1|1,mid+1,r);
pushup(cur);
}
void update(int l,int r,int cur) {
if(cur[t].flag) return;
if(cur[t].l==cur[t].r) {
cur[t].sum=(ll)sqrt(cur[t].sum);
if(t[cur].sum==1||cur[t].sum==0) cur[t].flag=1;
return;
}
int mid=cur[t].l+cur[t].r>>1;
if(l>mid) update(l,r,cur<<1|1);
else if(r<=mid) update(l,r,cur<<1);
else update(l,mid,cur<<1),update(mid+1,r,cur<<1|1);
pushup(cur);
}
ll query(int l,int r,int cur) {
if(cur[t].l>=l&&r>=cur[t].r)return cur[t].sum;
int mid=cur[t].l+cur[t].r>>1;
if(mid>=r) return query(l,r,cur<<1);
else if(l>mid) return query(l,r,cur<<1|1);
else return query(l,mid,cur<<1)+query(mid+1,r,cur<<1|1);
}
int main() {
scanf("%d",&n);
build(1,1,n);
scanf("%d",&m);
int opt,l,r;
while(m--) {
opt=rd();l=rd();r=rd();
if(l>r) std::swap(l,r);
if(opt==1)
printf("%lld
",query(l,r,1));
else update(l,r,1);
}
}