hdu-4027 Can you answer these queries?

<p><span style="font-size: 18px;">题意:<span style="color: rgb(54, 46, 43); font-family: Arial; line-height: 26px;">给定100000个数,两种操作,0 x y表示将x y这段的数字都开根号(向下取整),1 x y表示查询i j之间的所有值的和。。。(所有的和都不超过64位)..</span></span></p><p><span style="font-size: 18px;">思路:因为一个数不会超过2^63,所以开方次数最多不会超过8次就会成为1。tag标记该区间的数是否全为1,如果全为1就不再需要更新。其他的就是线段树的基本操作。</span></p><p><span style="font-size: 18px;">坑点就是没有告诉x,y,的大小。当x>y时需要变一下。</span></p>


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define LL long long
using namespace std;
const int N = 100000 + 10;
struct Tree
{
	LL sum;
	int L, R;
	int tag;//如果tag为1则表示该区间的数全部为1,不再继续更新
}tree[N*4];
void Build(int num, int Le, int Ri)
{
	tree[num].L = Le;
	tree[num].R = Ri;
	if (Le == Ri)
	{
		scanf("%I64d", &tree[num].sum);
		if (tree[num].sum == 1)
			tree[num].tag = 1;
		else
			tree[num].tag = 0;
		return;
	}
	int mid = (tree[num].L + tree[num].R) / 2;
	Build(num * 2, Le, mid);
	Build(num * 2 + 1, mid + 1, Ri);
	tree[num].sum = tree[num * 2 + 1].sum + tree[num * 2].sum;
	if (tree[num * 2].tag&&tree[num * 2 + 1].tag)//如左儿子和右儿子的区间的数为1
		tree[num].tag = 1;//tag更新为1,表示不再更新
	else
		tree[num].tag = 0;
}
void Update(int num, int Le, int Ri)
{
	if (tree[num].tag) return;//如果该区间的数全部为1了更新就没有意义
	if (tree[num].L == tree[num].R)
	{
		tree[num].sum = (LL)sqrt(tree[num].sum*1.0);//开方
	//	cout <<"******"<< tree[num].sum << ' ' << tree[num].L << ' ' << tree[num].R << endl;
		if (tree[num].sum == 1)
			tree[num].tag = 1;//tag更新
		return;
	}
	int  mid = (tree[num].L + tree[num].R) / 2;
	//这两个if包含了(1) Ri<=mid. (2) Le>mid.  (3) Le<=mid<Ri.这三种情况
	if (Le<=mid) Update(2 * num, Le, Ri);//这里为什么还是Le和Ri呢?因为更新的区间不能变。
	if (Ri>mid) Update(num * 2 + 1, Le, Ri);

	tree[num].sum = tree[num * 2].sum + tree[num * 2 + 1].sum;
	if (tree[2 * num].tag&&tree[num * 2 + 1].tag)
		tree[num].tag = 1;
}
LL Query(int num, int Le, int Ri)
{
	if (Le <= tree[num].L&&tree[num].R <= Ri)
	{
		return tree[num].sum;
	}
	int mid = (tree[num].L + tree[num].R) / 2;
	LL ans = 0;
	if (Le <= mid) ans += Query(num * 2, Le, Ri);//和上面的类似
	if (Ri > mid) ans += Query(num * 2 + 1, Le , Ri);
	return ans;
}
int main()
{
	int cas = 0;
	int n;
	while (scanf("%d", &n) != EOF)
	{
		Build(1, 1, n);
		int m;
		scanf("%d", &m);
		printf("Case #%d:\n", ++cas);
		for (int i = 1; i <= m; i++)
		{
			int Tag, Left, Right;
			int tem;
			scanf("%d%d%d", &Tag, &Left, &Right);
			if (Left>Right) { tem = Left; Left = Right; Right = tem; }//这里是最坑的地方,一定要有。
			if (Tag == 1)
				printf("%I64d\n", Query(1, Left, Right));
			else
				Update(1, Left, Right);
		}
		printf("\n");//每次结束有一个空行,贡献几次wa。
	}
	return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值