HDU 4027 Can you answer these queries?

题意:多组数据,0 操作表示将区间开根号,1操作表示区间求和。因为开根号是向下取整,2^64开根号,不超过10次就变成1了,所以说N个元素最多操作10*N次,就可以直接输出结果了,不用再进行多余的操作了。本题值得注意的点是:题目输入的l和r不完全保证r必大于l,所以需要进行比较;然后就是只能点更新,不能成段更新比如 sqrt(a)+sqrt(b) != sqrt(a+b)。其他的就是基础操作了。

#include <cmath>
#include <cstdio>
#include <algorithm>
#define ll long long
const int maxn = 1e5+5;
ll sum[maxn<<2];
void Build(int i, int l, int r) {
	if(l == r) {
		scanf("%lld", &sum[i]);
		return ;
	}
	int m = (l+r)>>1;
	Build(i<<1, l, m);
	Build(i<<1|1, m+1, r);
	sum[i] = sum[i<<1] + sum[i<<1|1];
	return ;
}
void Update(int i, int l, int r, int left, int right) {
	if(left == right) {
		sum[i] = sqrt(sum[i]);
		return ;
	}
	if(l <= left && r >= right && sum[i] == (right-left+1)) return ;//这一步会减少很多时间(精髓)
	int m = (left+right)>>1;
	if(l <= m) Update(i<<1, l, r, left, m);
	if(r > m) Update(i<<1|1, l, r, m+1, right);
	sum[i] = sum[i<<1] + sum[i<<1|1];
	return ;
}
ll Query(int i, int l, int r, int left, int right) {
	if(l <= left && r >= right) {
		return sum[i];
	}
	int m = (left+right)>>1;
	ll sum = 0;
	if(l <= m) sum += Query(i<<1, l, r, left, m);
	if(r > m) sum += Query(i<<1|1, l, r, m+1, right);
	return sum;
}
int main() {
	int N, M;
	int op, l, r;
	int Case = 1;
	while(~scanf("%d", &N)) {
		Build(1, 1, N);
		scanf("%d", &M);
		printf("Case #%d:\n", Case++);
		while(M--) {
			scanf("%d %d %d", &op, &l, &r);
			if(l > r) std::swap(l, r);
			if(op == 0) {
				Update(1, l, r, 1, N);
			}
			else {
				printf("%lld\n", Query(1, l, r, 1, N));
			}
		}
		printf("\n");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值