BZOJ 3211 线段树 区间更新 区间求和

传送门:题目

题意:

给一个序列,有两种操作:

  • 给区间[l,r],区间的每个值都开根号
  • 查询区间[l,r]sum

题解:

纯的线段树,区间更新,区间求和,套个模板就好。然后有个技巧:
109 10 9 5次根号就是1了,所以我们在建树或者更新的时候,发现值 1的时候,标记一下,
然后以后更新的时候,遇到已经被标记的点,说明这些点即使再开根号,还是原来的值,所以我们直接跳过这些被标记的点就好了。

坑点:

不能用cin,cout,要不会超时。

AC代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define debug(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
using namespace std;

const int maxn = 1e5 + 10;
int a[maxn];
bool flag[maxn << 2];
/******************线段树模板**********************/
long long SegTree[maxn << 2];
void BuildTree(int l, int r, int rt) {//建树,lr是总区间,rt是根结点一般为1
    if (l == r) {
        SegTree[rt] = a[l];//初始化叶节点
        if (SegTree[rt] <= 1)
            flag[rt] = true;
        return ;
    }
    int m = (l + r) >> 1;
    BuildTree(l, m, rt << 1);
    BuildTree(m + 1, r, rt << 1 | 1);
    SegTree[rt] = SegTree[rt << 1] + SegTree[rt << 1 | 1];
    flag[rt] = flag[rt << 1] & flag[rt << 1 | 1];
}
long long Query(int L, int R, int l, int r, int rt) {//区间查询,LR是查询区间,lr是总区间,rt是根结点一般为1
    if (l >= L && r <= R)
        return SegTree[rt];
    int m = (l + r) >> 1;
    long long ans = 0;
    if (L <= m)
        ans += Query(L, R, l, m, rt << 1);
    if (R > m)
        ans += Query(L, R, m + 1, r, rt << 1 | 1);
    return ans;
}
void Update(int L, int R, int l, int r, int rt) {
    if (flag[rt] == true)
        return;
    if (l == r) {
        SegTree[rt] = (long long)sqrt(SegTree[rt]);
        if (SegTree[rt] <= 1)
            flag[rt] = true;
        return;
    }
    int m = (l + r) >> 1;
    if (R <= m)
        Update(L, R, l, m, rt << 1);
    else if (L > m)
        Update(L, R, m + 1, r, rt << 1 | 1);
    else {
        Update(L, m, l, r, rt);
        Update(m + 1, R, l, r, rt);
    }
    SegTree[rt] = SegTree[rt << 1] + SegTree[rt << 1 | 1];
    flag[rt] = flag[rt << 1] & flag[rt << 1 | 1];
}
/******************线段树模板**********************/
int main(void) {
    int n, m, t1, t2, t3;
    scanf("%d",&n);
    for (int i = 1; i <= n; i++)
        scanf("%d",&a[i]);
    BuildTree(1, n, 1);
    scanf("%d",&m);
    while (m--) {
        scanf("%d%d%d",&t1,&t2,&t3);
        if (t1 == 1)
            printf("%lld\n",Query(t2, t3, 1, n, 1));
        else if (t1 == 2)
            Update(t2, t3, 1, n, 1);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值