洛谷P4145:https://www.luogu.org/problemnew/show/P4145
思路
这道题的重点在于sqrt(1)=1 一个限制条件
与正常线段树不同的是区间修改为开方
那么我们用一个数组记录每个区间的最大值 只有当这个区间的最大值大于1时才需要开方
因此 当我们更新到叶子节点时把每个区间的最大值和sum值开方即可
注意题目中说l可能大于r 要交换
代码
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> #include<cmath> using namespace std; #define ll long long #define maxn 100010 ll sum[maxn<<2],Max[maxn<<2],a[maxn]; ll n,m; void build(ll l,ll r,ll k) { if(l==r) { sum[k]=a[l]; Max[k]=sum[k];//叶子节点 return; } ll mid=(l+r)>>1; build(l,mid,k<<1); build(mid+1,r,k<<1|1); sum[k]=sum[k<<1]+sum[k<<1|1]; Max[k]=max(Max[k<<1],Max[k<<1|1]);//更新上层的值 return; } ll query(ll x,ll y,ll l,ll r,ll k)//常规询问 { if(x<=l&&r<=y) return sum[k]; ll res=0; ll mid=(l+r)>>1; if(x<=mid) res+=query(x,y,l,mid,k<<1); if(y>mid) res+=query(x,y,mid+1,r,k<<1|1); return res; } void update(ll x,ll y,ll l,ll r,ll k) { if(l==r)//叶子节点时 { sum[k]=sqrt(sum[k]); Max[k]=sqrt(Max[k]); return; } ll mid=(l+r)>>1; if(x<=mid&&Max[k<<1]>1) update(x,y,l,mid,k<<1);//满足最大值大于1 if(y>mid&&Max[k<<1|1]>1) update(x,y,mid+1,r,k<<1|1); sum[k]=sum[k<<1]+sum[k<<1|1];//更新上层的值 Max[k]=max(Max[k<<1],Max[k<<1|1]); } int main() { cin>>n; for(ll i=1;i<=n;i++) cin>>a[i]; build(1,n,1); cin>>m; for(ll i=1;i<=m;i++) { ll k,l,r; cin>>k>>l>>r; if(l>r)//交换 { int temp; temp=l; l=r; r=temp; } if(k==0) { update(l,r,1,n,1); } if(k==1) { cout<<query(l,r,1,n,1)<<endl; } } }