HDU4027 Can you answer these queries题解

这篇博客介绍了在处理区间查询和修改问题时遇到的特殊操作——开根号,由于开根号操作不具备结合律,导致不能直接使用常规的线段树优化方法。作者通过单点修改和剪枝技巧来解决这个问题,并提供了一个完整的C++代码实现。文章强调了这个问题的坑点和解决思路,适合对数据结构和算法感兴趣的读者学习。
摘要由CSDN通过智能技术生成

知识点:线段树(区间查询+区间修改)

这道题不同于以往的增减或乘除,增减乘除都是有结合律的,但是开根号是木有的(可能是我孤陋寡闻),所以只能单点修改,但是的话它又是有一定规律的,所以可以类似剪枝般省去一些步骤。
说明一下,这题并不难,但是非常非常坑qwd,坑点画红在下面

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
ll n,m,num[200000],tree[1800500],top=0;(常规操作)
class lktr{(打包好放一起,如果直接在类中定义数组会爆,只能开很小QAQ,所以放外面了)
	public:
	 void bd_tr(ll r=1,ll srt=1,ll edi=n){
		 if(srt==edi){
			tree[r]=num[srt];
			return ;
		}
		ll lf_r=2*r;
		ll rg_r=2*r+1;
		ll mid=(srt+edi)/2;
		bd_tr(lf_r,srt,mid);
		bd_tr(rg_r,mid+1,edi);
		tree[r]=tree[lf_r]+tree[rg_r];
	 }
	 void update(ll r,ll srt,ll edi,ll lf,ll rg){
		if(tree[r]==(edi-srt+1)||srt>rg||edi<lf)return ;(如果它的覆盖长度恰好等于区间和,说明这段区间全部一定是1(因为都大于0嘛))
		if(srt==edi) {
		tree[r]=(ll)sqrt(tree[r]*1.0);
		return ;
		}
		ll lf_r=2*r;
		ll rg_r=2*r+1;
		ll mid=(srt+edi)/2;
		if(lf<=mid)update(lf_r,srt,mid,lf,rg);
		if(mid<rg)update(rg_r,mid+1,edi,lf,rg);
		tree[r]=tree[lf_r]+tree[rg_r];
    }
	 ll query(ll r,ll srt,ll edi,ll lf,ll rg){
		if(srt>rg||edi<lf)return 0;
		if(lf<=srt&&edi<=rg)return tree[r];
		ll lf_r=2*r;
		ll rg_r=2*r+1;
		ll mid=(srt+edi)/2;
		ll sum=0;
		if(lf<=mid)sum+=query(lf_r,srt,mid,lf,rg);
		if(mid<rg)sum+=query(rg_r,mid+1,edi,lf,rg);
		return sum;
    }
	 void init(void){(初始化,多组数据)
		memset(tree,0,sizeof(tree));
		memset(num,0,sizeof(num));
		top=0;
    }
};
int main(){
	ll tot=0;
	lktr tr;
	while(scanf("%lld",&n)!=EOF){(这个是输入一直到文件结束)
		ll i,t,x,y;
		tot++;

		tr.init();
		for(i=1;i<=n;i++)
		 scanf("%lld",&num[i]);
		scanf("%lld",&m);
		tr.bd_tr();

		printf("Case #%lld:\n",tot);
		for(i=1;i<=m;i++){
			scanf("%lld%lld%lld",&t,&x,&y);
			if(x>y)swap(x,y);(x不一定小于y,要自己判断)
			if(t==0)tr.update(1,1,n,x,y);
			 else printf("%lld\n",tr.query(1,1,n,x,y));
		}
		printf("\n");(数据处理完后记得再输出个\n)
	}
}(这道题的全部数据最好都用longlong不然容易见祖宗捏QAQ)

总结:一道比较坑的题目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值