/* 区间修改 区间查询 可以用线段树搞 但是一般的标记下放对这个题好像不合适 只能改叶子 然后更新父亲(虽然跑的有点慢) 小优化:如果某个点是1 就不用再开方了 所以搞一个f[i]标记 i 这个点还需不需要处理下去 注意用longlong 还有就是数组开大 */ #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #define LL long long #define maxn 500010 using namespace std; LL n,m,num,x,y,z; LL a[maxn],f[maxn]; struct node { LL o; LL l,r; LL lc,rc; LL sum; }t[maxn*2]; LL init() { LL x=0; char s; bool f=0; s=getchar(); while(s<'0'||s>'9') { if(s=='-')f=1; s=getchar(); } while(s>='0'&&s<='9') { x=x*10+s-'0'; s=getchar(); } if(f==0)return x; else return -x; } void Build(LL ll,LL rr) { LL k=++num; t[k].o=k; t[k].l=ll;t[k].r=rr; if(ll!=rr-1) { t[k].lc=num+1; Build(ll,(ll+rr)/2); t[k].rc=num+1; Build((ll+rr)/2,rr); t[k].sum=t[t[k].lc].sum+t[t[k].rc].sum; } else t[k].sum=a[ll]; } void update(LL k,LL ll,LL rr) { if(f[k])return;//如果是1 说明儿子(如果有的话)要么是1 要么是0 不需要处理 直接返回 if(ll==rr-1) { t[k].sum=sqrt(t[k].sum); if(t[k].sum==1)f[k]=1; return; } LL mid=(ll+rr)/2; if(y<mid)update(t[k].lc,ll,(ll+rr)/2); if(z>=mid)update(t[k].rc,(ll+rr)/2,rr); t[k].sum=t[t[k].lc].sum+t[t[k].rc].sum; f[k]=f[t[k].lc]&&f[t[k].rc];//如果左右儿子都是1 那么父亲点也不用更新了. } LL find(LL k,LL ll,LL rr) { if(ll<=t[k].l&&rr>=t[k].r)return t[k].sum; LL ans=0; if(ll<(t[k].l+t[k].r)/2)ans+=find(t[k].lc,ll,rr); if(rr>(t[k].l+t[k].r)/2)ans+=find(t[k].rc,ll,rr); t[k].sum=t[t[k].lc].sum+t[t[k].rc].sum; return ans; } int main() { n=init(); for(int i=1;i<=n;i++) a[i]=init(); Build(1,n+1); m=init(); for(LL i=1;i<=m;i++) { x=init(); y=init(); z=init(); if(y>z)swap(y,z); if(x==0)update(1,1,n+1); if(x==1)printf("%lld ",find(1,y,z+1)); } }