<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;
}