HDU - 4027 -- Can you answer these queries?【线段树区间更新 + 剪枝】

题意

有n个敌方战舰,每一艘战列舰都标明其耐力值。对于我们的秘密武器的每一次攻击,它都可以通过使战舰的耐久力减到原耐久力值的平方根来降低其连续的耐久力。现在给出m个查询,每个查询包含T, X, Y
T = 1;查询x到y战舰的耐力总值
T = 0;x到y的每搜战舰的耐力值减到原来的一半

思路

ps:本以为是一个简单的区间修改 + 区间查询,结果T了。
看了题解才发现可以剪枝。当每个战舰的耐力值减少到1时,就不会再减少了,因为1的平方根就为1. 所以在区间修改的时候加一个判断条件即可。
还有一个坑点:当a > b时查出来的是 0,因为没这种区间,所以需要交换。

AC代码

#include
#include
#include
#include
#include
using namespace std;
#define IOS ios::sync_with_stdio(false)
#define ls  (rt << 1)
#define rs	(rt << 1 | 1)
typedef long long ll;
const int maxn = 100100;
ll sum[maxn << 2], arr[maxn];
void pushUp(int rt){
	sum[rt] = sum[ls] + sum[rs];
}
void build(int rt, int l, int r){
	if (l == r){
		sum[rt] = arr[l];
		return;
	}
	int m = (l + r) >> 1;
	build(ls, l, m);
	build(rs, m + 1, r);
	pushUp(rt);
}
void update(int rt, int l, int r, int L, int R){
	//剪枝:如果当前耐力值变成1,后面就不在变化。 成功踩坑
	if (sum[rt] == r - l + 1)	return; 
	if (l == r){
		sum[rt] = (ll)sqrt(sum[rt]);
		return;
	}
	int m = (l + r) >> 1;
	if (L <= m)		update(ls, l, m, L, R);
	if (m < R)		update(rs, m + 1, r, L, R);
	pushUp(rt);
}
ll query(int rt, int l, int r, int L , int R){
	if (L <= l && r <= R){
		return sum[rt];
	}
	int m = (l + r) >> 1;
	ll res = 0;
	if (L <= m)		res += query(ls, l, m, L, R);
	if (m < R)		res += query(rs, m + 1, r, L, R);
	return res;
}
void solve(){
	int n, m, cnt = 0;
	while (~scanf("%d", &n)){
		for (int i = 1; i <= n; ++i)	scanf("%lld", &arr[i]);
		build(1, 1, n);
		int k, l, r;
		printf("Case #%d:\n", ++cnt);
		scanf("%d", &m);
		while (m--){
			scanf("%d%d%d", &k, &l, &r);
			//再次踩坑
			if (l > r)	swap(l, r);
			if (k == 0){
				update(1, 1, n, l, r);
			} else {
				ll ans = query(1, 1, n, l, r);
				printf("%lld\n", ans);
			}
		}
		puts("");
	}
}
int main(){
	solve();
	return 0;
}

你可能感兴趣的:(#,线段树,树状数组)