题意:
给出一段序列和两种操作,第一种操作,将x,y区间的数均开平方,第二种操作,对x,y区间进行求和。
分析:
一开始还不敢用线段树做,因为纯线段树下来根暴力枚举复杂度差不了多少,但由于开方,所以在很少次的循环里就能达到1,所以就可以直接这么做了。但题目没有说名忍耐值的范围,要是0太多这个方法也不好使。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
ll tree[maxn<<2];
void build(int l,int r,int i){
if(l==r){
scanf("%lld",&tree[i]);
return;
}
int mid=l+r>>1;
build(l,mid,i<<1);
build(mid+1,r,i<<1|1);
tree[i]=tree[i<<1]+tree[i<<1|1];
}
void change(int tl,int tr,int l,int r,int i){
if(tl>r||tr<l) return ;
if(tl<=l&&r<=tr&&tree[i]<=r-l+1) return; //这部很关键。
if(l==r){
tree[i]=sqrt(1.0*tree[i]);
return;
}
int mid=l+r>>1;
change(tl,tr,l,mid,i<<1);
change(tl,tr,mid+1,r,i<<1|1);
tree[i]=tree[i<<1]+tree[i<<1|1];
}
ll query(int tl,int tr,int l,int r,int i){
if(tl>r||tr<l) return 0;
if(tl<=l&&r<=tr) return tree[i];
int mid=l+r>>1;
return query(tl,tr,l,mid,i<<1)+query(tl,tr,mid+1,r,i<<1|1);
}
int main(){
int n,m,cs=1;
while(scanf("%d",&n)!=EOF){
memset(tree,0,sizeof tree);
build(1,n,1);
scanf("%d",&m);
printf("Case #%d:\n",cs++);
while(m--){
int f,x,y;
scanf("%d%d%d",&f,&x,&y);
if(x>y) swap(x,y); //注意着。
if(f==1){
printf("%lld\n",query(x,y,1,n,1));
}else{
change(x,y,1,n,1);
}
}
printf("\n");
}
}
来源:CSDN
作者:Combatting
链接:https://blog.csdn.net/qq_40679299/article/details/83118679