by luogu
可用于练习线段树
这里涉及到了开方操作
和 + * 不同,它的运算次数大大减小
只有大概8次操作就会到1
而1无论开多少次的方
都是1
所以可以去掉懒标了
这里的mark所记录的是区间最大值
若最大值都为1,那么也就吗,没有必要再进行计算
但是修改的话
还是需要一次到底(l==r)
这次就懒得打注释了QAQ
#include<bits/stdc++.h> #define int long long #define mid ((l+r)>>1) using namespace std; int c[400011]; int a[400011],mark[400011]; void build(int x,int l,int r) { if(l==r) { a[x]=c[l]; mark[x]=c[l]; return ; } build((x<<1),l,mid); build((x<<1)|1,mid+1,r); a[x]=a[x<<1]+a[(x<<1)|1]; mark[x]=max(mark[x<<1],mark[(x<<1)|1]); return ; } void pl(int x,int l,int r,int s,int e) { if(s>r||e<l) return ; if(l==r) { a[x]=sqrt(a[x]); mark[x]=a[x]; return ; } // push(x,l,r); if(mark[x<<1]>1&&mid>=s) pl((x<<1),l,mid,s,e); if(mark[(x<<1)|1]>1&&mid<e) pl((x<<1)|1,mid+1,r,s,e); a[x]=a[x<<1]+a[(x<<1)|1]; mark[x]=max(mark[x<<1],mark[(x<<1)|1]); return ; } int query(int x,int l,int r,int s,int e) { if(s>r||e<l) return 0; if(s<=l&&r<=e) return a[x]; //push(x,l,r); return query((x<<1),l,mid,s,e)+query((x<<1)+1,mid+1,r,s,e); } int n,m; signed main() { ios::sync_with_stdio(false); cin>>n; for(int i=1;i<=n;i++) cin>>c[i]; build(1,1,n); cin>>m; for(int i=1;i<=m;i++) { int q,w,e; cin>>q>>w>>e; if(w>e) swap(w,e); if(q) cout<<query(1,1,n,w,e)<<endl; else pl(1,1,n,w,e); } return 0; }