题目
分析
每个数不断开根下取整,最终会变成 1 1 1,显而易见的是只需要开极少的次数一个数就能变成一,这个次数是 log 2 log 2 n + 1 \log_2\log_2 n + 1 log2log2n+1。因此线段树区间修改时如果该区间没有全部变成 1 1 1,就暴力一个一个改即可。
代码
#include <bits/stdc++.h>
typedef long long LL;
LL Read() {
LL x = 0; bool f = false; char c = getchar();
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = x * 10 + (c ^ 48), c = getchar();
return f ? -x : x;
}
const int MAXN = 100000;
int N, Q;
#define lch (u << 1)
#define rch (u << 1 | 1)
struct Node {
LL tot;
bool flg;
Node operator + (const Node &other) const {
return { tot + other.tot, flg && other.flg };
}
} T[MAXN * 4 + 5];
void Build(const int &u, const int &l, const int &r) {
if (l == r) {
T[u].flg = false;
T[u].tot = Read();
return;
}
int mid = (l + r) >> 1;
Build(lch, l, mid);
Build(rch, mid + 1, r);
T[u] = T[lch] + T[rch];
}
void Sqrt(const int &u, const int &l, const int &r, const int &lft, const int &rgt) {
if (T[u].flg) return;
if (l == r) {
T[u].tot = (LL)sqrt(T[u].tot + 0.1);
if (T[u].tot == 1) T[u].flg = true;
return;
}
int mid = (l + r) >> 1;
if (lft <= mid) Sqrt(lch, l, mid, lft, rgt);
if (mid + 1 <= rgt) Sqrt(rch, mid + 1, r, lft, rgt);
T[u] = T[lch] + T[rch];
}
LL Query(const int &u, const int &l, const int &r, const int &lft, const int &rgt) {
if (lft <= l && r <= rgt) return T[u].tot;
int mid = (l + r) >> 1; LL ret = 0;
if (lft <= mid) ret = Query(lch, l, mid, lft, rgt);
if (mid + 1 <= rgt) ret += Query(rch, mid + 1, r, lft, rgt);
return ret;
}
int main() {
// int Case = 0;
while (~scanf("%d", &N)) {
Build(1, 1, N);
Q = Read();
// printf("Case #%d:\n", ++Case);
while (Q--) {
int opt = Read(), l = Read(), r = Read();
if (l > r) std::swap(l, r);
if (opt) printf("%lld\n", Query(1, 1, N, l, r));
else Sqrt(1, 1, N, l, r);
}
}
return 0;
}