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

来源:互联网 发布:js触发按钮点击事件 编辑:程序博客网 时间:2024/05/22 07:10

题目大意:给你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 0