hdu4027 Can you answer these queries?(线段树+暴力开根)

博客围绕一道题目展开,题目包含n个数和m次操作,操作有对区间暴力开根和询问区间和两种。思路源于傅老师,题解采用暴力开根,维护区间是否被开成1,若为1则不往子区间开,复杂度约为O(6*n),还给出了代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

n(n<=1e5)个数,m(m<=1e5)次操作,题目保证\sum a_{i}小于2^{63}

操作分两种,

1 对[l,r]暴力开根一次

2 询问[l,r]的和

思路来源

傅老师

题解

暴力开根,维护整个区间有没有被开成1

如果被开成1了就不往子区间开了,

注意到1e18的数开个6次,就被开成1了,

复杂度大概是O(6*n)叭

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
ll a[maxn];
ll sum[maxn*5];
bool ok[maxn*5];//该区间是否整个区间都被开根为1
int cas,n,m;
int op,l,r;
void pushup(int p)
{
	sum[p]=sum[p<<1]+sum[p<<1|1];
	ok[p]=ok[p<<1]&ok[p<<1|1];
}
void build(int p,int l,int r)
{
	sum[p]=ok[p]=0; 
	if(l==r)
	{
		sum[p]=a[l];
		if(sum[p]==1)ok[p]=1;
		else ok[p]=0;
		return;
	}
	int mid=(l+r)/2;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	pushup(p);
}  
void update(int p,int l,int r,int ql,int qr)
{
	if(ok[p])return;//整个区间都被开成1了 
	if(l==r)
	{
		sum[p]=sqrt(sum[p]);
		if(sum[p]==1)ok[p]=1;
		else ok[p]=0;
		return;
	}
	int mid=(l+r)/2;
	if(ql<=mid)update(p<<1,l,mid,ql,qr);
	if(qr>mid)update(p<<1|1,mid+1,r,ql,qr);
	pushup(p);
}
ll ask(int p,int l,int r,int ql,int qr)
{
	if(ql<=l&&r<=qr)return sum[p];
	ll ans=0;
	int mid=(l+r)/2;
	if(ql<=mid)ans+=ask(p<<1,l,mid,ql,qr);
	if(qr>mid)ans+=ask(p<<1|1,mid+1,r,ql,qr);
	return ans;
}
int main()
{
	while(~scanf("%d",&n))
	{
		for(int i=1;i<=n;++i)
		scanf("%lld",&a[i]);
		build(1,1,n);
		scanf("%d",&m); 
		printf("Case #%d:\n",++cas);
		for(int i=1;i<=m;++i)
		{
			scanf("%d%d%d",&op,&l,&r);
			if(l>r)swap(l,r);
			if(op==0)update(1,1,n,l,r);
			else printf("%lld\n",ask(1,1,n,l,r));
		}
		puts("");
	}
	return 0;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值