版权声明:欢迎转载 https://blog.csdn.net/yandaoqiusheng/article/details/88607116
题目链接:传送门
区间求和,区间开方
显然一个数开不了几次就变成1了
所以再维护一个块内是不是都变成了1
到时候就可以少更新许多
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <complex>
#include <algorithm>
#include <climits>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define A 1000010
#define B 2010
using namespace std;
typedef long long ll;
int n, bl[A], sq[A], s[A], vis[A], m, a, b, c, opt;
void sqr(int a, int b, int c) {
if (!vis[bl[a]]) {
for (int i = a; i <= min(bl[a] * m, b); i++) s[bl[a]] -= sq[i], sq[i] = sqrt(sq[i]), s[bl[a]] += sq[i];
vis[bl[a]] = 1;
for (int i = (bl[a] - 1) * m + 1; i <= bl[a] * m; i++)
if (sq[i] > 1) {
vis[bl[a]] = 0;
break;
}
}
if (bl[a] != bl[b] and !vis[bl[b]]) {
for (int i = (bl[b] - 1) * m + 1; i <= b; i++) s[bl[b]] -= sq[i], sq[i] = sqrt(sq[i]), s[bl[b]] += sq[i];
vis[bl[b]] = 1;
for (int i = (bl[b] - 1) * m + 1; i <= bl[b] * m; i++)
if (sq[i] > 1) {
vis[bl[b]] = 0;
break;
}
}
for (int i = bl[a] + 1; i <= bl[b] - 1; i++) {
if (vis[i]) continue;
vis[i] = 1; s[i] = 0;
for (int j = (i - 1) * m + 1; j <= i * m; j++) {
sq[j] = sqrt(sq[j]);
s[i] += sq[j];
if (sq[j] > 1) vis[i] = 0;
}
}
}
ll ask(int a, int b, ll ans = 0) {
for (int i = a; i <= min(bl[a] * m, b); i++) ans += sq[i];
if (bl[a] != bl[b])
for (int i = (bl[b] - 1) * m + 1; i <= b; i++) ans += sq[i];
for (int i = bl[a] + 1; i <= bl[b] - 1; i++) ans += s[i];
return ans;
}
int main(int argc, char const *argv[]) {
scanf("%d", &n); m = sqrt(n);
for (int i = 1; i <= n; i++) bl[i] = (i - 1) / m + 1;
for (int i = 1; i <= n; i++) scanf("%d", &sq[i]), s[bl[i]] += sq[i];
for (int i = 1; i <= n; i++) {
scanf("%d%d%d%d", &opt, &a, &b, &c);
if (!opt) sqr(a, b, c);
else printf("%lld\n", ask(a, b));
}
return 0;
}