BZOJ 3211: 花神游历各国 线段树区间开根

Description
这里写图片描述
Input
这里写图片描述
Output

每次x=1时,每行一个整数,表示这次旅行的开心度

Sample Input
4

1 100 5 5

5

1 1 2

2 1 2

1 1 2

2 2 3

1 1 4

Sample Output
101

11

11

HINT

对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9

线段树经典套路了。偶然碰到了,再写一次

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
#define lson l,m,o*2
#define rson m+1,r,o*2+1
namespace segmenttree{
    int c[maxn*4];
    long long sum[maxn*4];
    void pushup(int o){
        sum[o] = sum[o*2] + sum[o*2+1];
        c[o] = c[o*2] || c[o*2+1] ? 1: 0;
    }
    void build(int l, int r, int o){
        if(l == r){
            scanf("%lld", &sum[o]);
            c[o] = sum[o] > 1 ? 1: 0;
            return;
        }
        int m = (l + r) / 2;
        build(lson);
        build(rson);
        pushup(o);
    }
    void update(int L, int R, int l, int r, int o){
        if(!c[o]) return;
        if(l == r){
            sum[o] = sqrt(sum[o]);
            if(sum[o] <= 1) c[o] = 0;
            return;
        }
        int m = (l + r) / 2;
        if(L <= m && c[o*2]) update(L, R, lson);
        if(m < R && c[o*2+1]) update(L, R, rson);
        pushup(o);
    }
    long long query(int L, int R, int l, int r, int o){
        if(L <= l && r <= R) return sum[o];
        int m = (l + r) / 2;
        if(R <= m) return query(L, R, lson);
        else if(L > m) return query(L, R, rson);
        else{
            return query(L, m, lson) + query(m + 1, R, rson);
        }
    }
}
using namespace segmenttree;

int main(){
    int n, m;
    scanf("%d", &n);
    build(1, n, 1);
    scanf("%d", &m);
    for(int i = 1; i <= m; i++){
        int cmd, l, r;
        scanf("%d%d%d", &cmd, &l, &r);
        if(cmd == 1) printf("%lld\n", query(l, r, 1, n, 1));
        else update(l, r, 1, n, 1);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值