大致题意:
支持区间开方(向下取整),区间求和
题解:
就是一道线段树的板子题,只是需要明白怎么进行区间开方效率比较高。
由于一个数如果对其进行开方大概搞个几次就会变为1,然后就不需要再对其进行开方了(1 再怎么弄也只能是 1)
我们怎么用程序实现呢?很简单只需要维护一个区间最大值就好了,如果最大值== 1 ,显然整个区间都可以不往下搞了
顺便bibi一句:区间取模一个道理
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#define in read()
#define ULL unsigned long long
#define N 100009
#define lc (k<<1)
#define rc ((k<<1)+1)
using namespace std;
int n,m;
ULL sum[4*N],maxn[4*N],a[N];
inline ULL read(){
char ch;int f=1;
ULL res=0;
while((ch=getchar())<'0'||ch>'9')
if(ch=='-') f=-1;
while(ch>='0'&&ch<='9')
{
res=res*10+ch-'0';
ch=getchar();
}
return f==1?res:-res;
}
void build(int k,int l,int r){
if(l==r){
maxn[k]=a[l];
sum[k]=a[l];
return;
}
int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);
sum[k]=sum[lc]+sum[rc];
maxn[k]=max(maxn[lc],maxn[rc]);
}
void sqrtt(int k,int l,int r,int x,int y){
if(maxn[k]==1) return;
if(l==r){
maxn[k]=(ULL)sqrt(maxn[k]);//注意sqrt函数的返回值是实数类型的,我们强制转化一下
//又由于整数类的运算默认向下取整,就可以不管了
sum[k]=maxn[k];
return;
}
int mid=l+r>>1;
if(x<=mid) sqrtt(lc,l,mid,x,y);
if(y>mid) sqrtt(rc,mid+1,r,x,y);
sum[k]=sum[lc]+sum[rc];
maxn[k]=max(maxn[lc],maxn[rc]);
}
ULL querysum(int k,int l,int r,int x,int y){
if(l>=x&&r<=y) return sum[k];
ULL res=0;
int mid=l+r>>1;
if(x<=mid) res+=querysum(lc,l,mid,x,y);
if(y>mid) res+=querysum(rc,mid+1,r,x,y);
return res;
}
int main(){
n=in;
int i,j,k;
for(i=1;i<=n;++i) a[i]=in;
build(1,1,n);
m=in;
for(i=1;i<=m;++i){
int l,r;
k=in;l=in;r=in;
if(l>r) swap(l,r);
if(k==0) sqrtt(1,1,n,l,r);
else printf("%lld\n",querysum(1,1,n,l,r));
}
return 0;
}