[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;
}

 

posted @ 2018-04-03 20:23  xayata  阅读(180)  评论(0编辑  收藏  举报