hdu 4027(区间更新)

题意:有n个数字,q次询问,两种操作0 x y 把区间[x,y]全部开根号,1 x y 询问区间[x,y]数字和。
题解:q的范围到100000,题目中说数字最大2^63,所以一个数字最多开7次根就是1不再变化了,所以用一个线段树维护每个数字还能开多少次根号,区间维护最大值,如果某个区间的最大次数已经是0,就不用更新了。一直wa,然后发现有可能x > y,吐血。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
const int N = 100005;
int n, q, num[N << 2], b[N];
ll arr[N], tree[N << 2], flag[N << 2];

void pushup(int k) {
    tree[k] = tree[k * 2] + tree[k * 2 + 1];
    num[k] = max(num[k * 2], num[k * 2 + 1]);
}

void build(int k, int left, int right) {
    if (left == right) {
        tree[k] = arr[left];
        num[k] = b[left];
        return;
    }
    int mid = (left + right) / 2;
    build(k * 2, left, mid);
    build(k * 2 + 1, mid + 1, right);
    pushup(k);
}

void modify(int k, int left, int right, int l, int r) {
    if (l <= left && right <= r) {
        if (num[k] == 0) {
            return;
        }
        if (left == right) {
            tree[k] = sqrt(tree[k]);
            num[k]--;
        }
        else {
            int mid = (left + right) / 2;
            if (l <= mid)
                modify(k * 2, left, mid, l, r);
            if (r > mid)
                modify(k * 2 + 1, mid + 1, right, l, r);
            pushup(k);
        }
        return;
    }
    int mid = (left + right) / 2;
    if (l <= mid)
        modify(k * 2, left, mid, l, r);
    if (r > mid)
        modify(k * 2 + 1, mid + 1, right, l, r);
    pushup(k);
}

ll query(int k, int left, int right, int l, int r) {
    if (l <= left && right <= r)
        return tree[k];
    int mid = (left + right) / 2;
    ll res = 0;
    if (l <= mid)
        res += query(k * 2, left, mid, l, r);       
    if (r > mid)
        res += query(k * 2 + 1, mid + 1, right, l, r);
    pushup(k);
    return res;
}

int main() {
    int cas = 1;
    while (scanf("%d", &n) == 1) {
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &arr[i]);
            ll temp = arr[i];
            int cnt = 0;
            while (temp != 1) {
                cnt++;
                temp = sqrt(temp);
            }
            b[i] = cnt;
        }
        build(1, 1, n);
        scanf("%d", &q);
        int op, l, r;
        printf("Case #%d:\n", cas++);
        while (q--) {
            scanf("%d%d%d", &op, &l, &r);
            if (l > r) swap(l, r);
            if (op == 0)
                modify(1, 1, n, l, r);
            else {
                printf("%lld\n", query(1, 1, n, l, r));
            }
        }
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值