0817-线段树板子-洛谷P4145-上帝造题的7分钟2

传送门

大致题意:

   支持区间开方(向下取整),区间求和

题解:

就是一道线段树的板子题,只是需要明白怎么进行区间开方效率比较高。

由于一个数如果对其进行开方大概搞个几次就会变为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;
}

猜你喜欢

转载自blog.csdn.net/weixin_42557561/article/details/81381819