题意:把一组舰队看成是线段上的端点,有一种秘密武器,每次可以攻击一个区间上的船,然后他们的防御力x减低为sqrt(x).
做法:最多只能有7次攻击有效。所以用带点更新吧,一遇到区间防御力总和为len(区间中含有舰船的个数),就停止更新,因为这个区间所有的船的防御力已经只剩1了,这么一来,最后的时间复杂度不会太高
#include <cstdio>
#include <cstring>
#include <cmath>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define left l, m, x << 1
#define right m + 1, r, x << 1 | 1
//有效攻最多七下。。。
typedef __int64 LL;
const int LMT = 100003;
LL sum[LMT << 2];
struct __node
{
int l, r, len;
}node[LMT << 2];
inline LL get(void)
{
LL res = 0;
char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9')
{
res = res * 10 + ch - '0';
ch = getchar();
}
return res;
}
void build(int l, int r, int x)
{
node[x].l = l;
node[x].r = r;
node[x].len = r - l + 1;
if(l == r)
{
sum[x] = get();
return ;
}
int m = (l + r) >> 1;
build(left);
build(right);
sum[x] = sum[x << 1] + sum[x << 1 | 1];
}
LL query(int L, int R, int x)
{
if (L <= node[x].l && node[x].r <= R) return sum[x];
int m = (node[x].l + node[x].r) >> 1;
LL res = 0;
if (L <= m) res += query(L, R, x << 1);
if (R > m) res += query(L, R, x << 1 | 1);
return res;
}
void update(int L, int R, int x)
{
if(sum[x] == node[x].len) return;
if(node[x].l == node[x].r)
{
sum[x] = (LL)sqrt(1.0 * sum[x]);
return;
}
int m = (node[x].l + node[x].r) >> 1;
if (L <= m) update(L, R, x << 1);
if (R > m) update(L, R, x << 1 | 1);
sum[x] = sum[x << 1] + sum[x << 1 | 1];
}
int main(void)
{
int n, q, ord, l, r, I = 1;
while(~scanf("%d", &n))
{
build(1, n, 1);
scanf("%d", &q);
printf("Case #%d:\n", I++);
while(q--)
{
scanf("%d%d%d", &ord, &l, &r);
if(l > r)
{
l = l ^ r;
r = l ^ r;
l = l ^ r;
}
if(ord) printf("%I64d\n", query(l, r, 1));
else update(l, r, 1);
}
printf("\n");
}
return 0;
}