[HDU4027] Can you answer these queries?

2017年9月8日

给你 n 个数,依次标号为 1, 2, … , n。
有两种操作,一种是对区间 x, y 内的每个数进行开方,开方后的数取整数;另一种是问区间 x, y 内数的和。

虽然说每个数都可以很大,但是开方开到一定次数后就变成 1,再对 1 开方也就没必要了。因此用线段树,增加一个值来看所操作区间下的数是否都为 1,若都是 1 也就没必要再对其进行操作了。

#include <bits/stdc++.h>
using namespace std;
typedef long long i64;
const int N = 100005;
struct edge {
  i64 sum;
  bool flag;
} e[N << 2];
void build(int l, int r, int rt)
{
  if (l == r) {
    scanf("%lld", &e[rt].sum);
    e[rt].flag = (e[rt].sum == 1) ? 1 : 0;
  } else {
    int m = l + r >> 1;
    build(l, m, rt << 1);
    build(m + 1, r, rt << 1 | 1);
    e[rt].sum = e[rt << 1].sum + e[rt << 1 | 1].sum;
    e[rt].flag = e[rt << 1].flag & e[rt << 1 | 1].flag;
  }
}
void update(int ll, int rr, int l, int r, int rt)
{
  if (e[rt].flag) {
    return;
  }
  if (l == r) {
    e[rt].sum = (int) sqrt(1.0 * e[rt].sum);
    e[rt].flag = (e[rt].sum == 1) ? 1 : 0;
    return;
  }
  int m = l + r >> 1;
  if (ll <= m)
    update(ll, rr, l, m, rt << 1);
  if (rr > m)
    update(ll, rr, m + 1, r, rt << 1 | 1);
  e[rt].sum = e[rt << 1].sum + e[rt << 1 | 1].sum;
  e[rt].flag = e[rt << 1].flag & e[rt << 1 | 1].flag;
}
i64 query(int ll, int rr, int l, int r, int rt)
{
  if (ll <= l && r <= rr) {
    return e[rt].sum;
  }
  i64 res = 0;
  int m = l + r >> 1;
  if (ll <= m)
    res += query(ll, rr, l, m, rt << 1);
  if (rr > m)
    res += query(ll, rr, m + 1, r, rt << 1 | 1);
  return res;
}
int main()
{
  int n, cas = 1;
  while (~scanf("%d", &n)) {
    printf("Case #%d:\n", cas++);
    build(1, n, 1);
    int m;
    scanf("%d", &m);
    while (m--) {
      int a, x, y;
      scanf("%d %d %d", &a, &x, &y);
      if (x > y)
        swap(x, y);
      if (a) {
        printf("%lld\n", query(x, y, 1, n, 1));
      } else {
        update(x, y, 1, n, 1);
      }
    }
    puts("");
  }
  return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注