[Luogu] 花神游历各国
https://www.luogu.org/problemnew/show/P4145
线段树区间求和 + 区间开根号
对1e9的数开根号下取整用不了几次就会<=1
因此暴力开根号,记录区间最大值是否已经<=1
#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; #define LL long long #define gc getchar() int n, Ty; LL data[N]; LL sum[N << 2]; LL Max[N << 2]; LL Answer; inline LL read() { LL x = 0; char c = gc; while(c < '0' || c > '9') c = gc; while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x; } struct Node { #define lson jd << 1 #define rson jd << 1 | 1 void Up(int jd) {sum[jd] = sum[lson] + sum[rson]; Max[jd] = max(Max[lson], Max[rson]);} void Build_tree(int l, int r, int jd) { if(l == r) {sum[jd] = data[l]; Max[jd] = data[l]; return ;} int mid = (l + r) >> 1; Build_tree(l, mid, lson); Build_tree(mid + 1, r, rson); Up(jd); } void Sec_G(int l, int r, int jd, int x, int y) { if(Max[jd] <= 1) return ; if(l == r) {sum[jd] = floor(sqrt(sum[jd])); Max[jd] = sum[jd]; return ;} int mid = (l + r) >> 1; if(x <= mid) Sec_G(l, mid, lson, x, y); if(y > mid) Sec_G(mid + 1, r, rson, x, y); Up(jd); } void Sec_A(int l, int r, int jd, int x, int y) { if(x <= l && r <= y) {Answer += sum[jd]; return ;} int mid = (l + r) >> 1; if(x <= mid) Sec_A(l, mid, lson, x, y); if(y > mid) Sec_A(mid + 1, r, rson, x, y); } }Seg_tree; int main() { n = read(); for(int i = 1; i <= n; i ++) data[i] = read(); Seg_tree.Build_tree(1, n, 1); Ty = read(); while(Ty --) { int opt = read(), x = read(), y = read(); if(x > y) swap(x, y); if(opt == 0) Seg_tree.Sec_G(1, n, 1, x, y); else {Answer = 0; Seg_tree.Sec_A(1, n, 1, x, y); cout << Answer << "\n";} } return 0; }