0
点赞
收藏
分享

微信扫一扫

HDU - 4027 Can you answer these queries?(线段树)

香小蕉 2023-04-07 阅读 55


题目大意:给你N个数,两种操作
0 l r:[l,r]内的所有数开根
1 l r:[l,r]内的数字的和

解题思路:不断开根的话,最多只需要6次,6次以上的,都是1了,所以维护的是当前区间被开了几次根的和
这个可以先预处理下,先预处理所有所有情况的开根和(不超过7次),然后在用一个标记,标记该区间被开了几次根,求和的时候就可以依据此标记来找和了

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;
typedef long long LL;
const int N = 100010;
LL sum[10][N << 2], val[N], level;
int add[N << 2], cnt[N << 2];
int n, q;

void PushUp(int u) {
    for (int i = 0; i <= level; i++)
        sum[i][u] = sum[i][u << 1] + sum[i][u << 1 | 1];
}

void build(int u, int l, int r) {
    add[u] = cnt[u] = 0;
    if (l == r) {
        sum[0][u] = val[l];
        if (val[l] == 0) {
            for (int i = 1; i <= level; i++)
                sum[i][u] =  0;
            return ;
        }
        int i;
        for (i = 1; sum[i - 1][u] > 1; i++) sum[i][u] = sqrt((double)sum[i - 1][u]);
        for (; i <= level; i++) sum[i][u] = 1;
        return ;
    }
    int mid = (l + r) >> 1;
    build(u << 1, l, mid);
    build(u << 1 | 1, mid + 1, r);
    PushUp(u);
}

void PushDown(int u) {
    if (add[u] != 0) {
        add[u << 1] += add[u];
        add[u << 1 | 1] += add[u];
        cnt[u << 1] += add[u];
        cnt[u << 1 | 1] += add[u];
        add[u] = 0;
    }
}

void Modify(int u, int l, int r, int L, int R) {
    if (l == L && r == R) {
        add[u] += 1;
        cnt[u] += 1;
        return ;
    }

    PushDown(u);    
    int mid = (l + r) >> 1;
    if (R <= mid) Modify(u << 1, l, mid, L, R);
    else if (L > mid) Modify(u << 1 | 1, mid + 1, r, L, R);
    else {
        Modify(u << 1, l, mid, L, mid);
        Modify(u << 1 | 1, mid + 1, r, mid + 1, R);
    }
}

LL Query(int u, int l, int r, int L, int R) {
    if (L == l && r == R) {
        if (cnt[u] > level) cnt[u] = level;
        if (cnt[u] == level || l == r) return sum[cnt[u]][u];
        PushDown(u);
        int mid = (l + r) >> 1;
        return Query(u << 1, l, mid, l, mid) + Query(u << 1 | 1, mid + 1, r, mid + 1, r);
    }
    PushDown(u);
    int mid = (l + r) >> 1;
    if (R <= mid) return Query(u << 1, l, mid, L, R);
    else if (L > mid) return Query(u << 1 | 1, mid + 1, r, L, R);
    else return Query(u << 1, l, mid, L, mid) + Query(u << 1 | 1, mid + 1, r, mid + 1, R);
}

void init() {
    LL Max = 0;
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &val[i]);
        Max = max(Max, val[i]);
    }

    for (level = 1; Max > 1; level++) Max = sqrt((double)Max);
    build(1, 1, n);
}

int cas = 1;
void solve() {
    scanf("%d", &q);
    int op, a, b;
    printf("Case #%d:\n", cas++);
    while (q--) {
        scanf("%d%d%d", &op, &a, &b);
        if (a > b) swap(a, b);
        if (op) printf("%lld\n", Query(1, 1, n, a, b));
        else Modify(1, 1, n, a, b);
    }
    printf("\n");
}

int main() {
    while (scanf("%d", &n) != EOF) {
        init();
        solve();
    }
    return 0;
}


举报

相关推荐

0 条评论