HDU4027:Can you answer these queries?(线段树 单点更新 区间求和)

题意:

n列邪恶的战舰的都被排列在一个线前的战斗。我们的指挥官决定使用我们的秘密武器消灭战列舰。

每个战列舰可以标记值的耐力。

我们的秘密武器,每一次的攻击一个区间,它可以使其区间内的战舰耐力降低到原始值的平方根(向下取整)。

求区间和。

思路: 单点更新 区间求和 当叶子为1或0时可以标记不再更新 那么整个区间的叶子全为0 或 1 时 也不用更新 优化时间

注意: 给出的区间可能会使 人 r >l 。

AC code:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
#define N 1000100
struct node
{
	LL l;
	LL r;
	LL sum;
}tree[N << 2];
bool used[N << 2];  //标记数组 表示区间内的值 是否全为0或1
void build(LL root, LL l, LL r)
{
	tree[root].l = l;
	tree[root].r = r;
	if (l == r)
	{
		scanf("%lld", &tree[root].sum);  //节点输入,优化时间(用数组长度较大的时候会TLE)
		if (tree[root].sum <= 1)       //假如叶子节点的值 为0或1 标记 不再更新它
		{
			used[root] = true;
		}
		return;
	}
	LL mid = (l + r) / 2;
	build(root * 2, l, mid);
	build(root * 2 + 1, mid + 1, r);
	tree[root].sum = tree[root * 2].sum + tree[root * 2 + 1].sum;
	if (used[root * 2] && used[root * 2 + 1]) { used[root] = true; }   //假如区间内的左右区间内的叶子节点值 全部为0或1 标记不再更新它
}
void update(LL root, LL l, LL r)
{
	if (used[root])        return;
	LL mid = (tree[root].l + tree[root].r) / 2;
	if (tree[root].l == tree[root].r)
	{
		tree[root].sum = sqrt(tree[root].sum);
		if (tree[root].sum <= 1) { used[root] = true; }  //假如叶子节点的值更新后 为0或1 标记 不再更新它
		return;
	}
	if (l <= mid && used[root * 2] == false)
	{
		update(root * 2, l, r);
	}
	if (r > mid && used[root * 2 + 1] == false)
	{
		update(root * 2 + 1, l, r);
	}
	tree[root].sum = tree[root * 2].sum + tree[root * 2 + 1].sum;
	if (used[root * 2] && used[root * 2 + 1]) { used[root] = true; }  //假如更新后的区间内的左右区间内的叶子节点值 全部为0或1 标记不再更新它
}
LL query(LL root, LL l, LL r)
{
	LL ans = 0;
	if (l <= tree[root].l && tree[root].r <= r)
	{
		return tree[root].sum;
	}
	LL mid = (tree[root].l + tree[root].r) / 2;
	if (l <= mid)
	{
		ans += query(root * 2, l, r);
	}
	if (r > mid)
	{
		ans += query(root * 2 + 1, l, r);
	}
	return ans;
}
int main()
{
	LL i, f, x, y, n, m, k = 1;
	while (scanf("%lld", &n) != EOF)
	{
		memset(used, false, sizeof(used));
		memset(tree, 0, sizeof(used));
		printf("Case #%lld:\n", k++);
		build(1, 1, n);
		scanf("%lld", &m);
		while (m--)
		{
			scanf("%lld%lld%lld", &f, &x, &y);
			if (x > y) { swap(x, y); }
			if (!f)
			{
				update(1, x, y);
			}
			else
			{
				printf("%lld\n", query(1, x, y));
			}
		}
		printf("\n");
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值