GSS4-Can you answer these queries IV

Description

You are given a sequence \(a\) of \(n\) positive integers. Their sum will be less than \(10^18\). On this sequence you have to apply \(m\) operations:

  • For given \(x, y\), for each elements between the \(x-th\) and the \(y-th\) ones (inclusively, counting from \(1\)) , modify it to its positive square root (rounded down to the nearest integer).
  • For given \(x, y\), query the sum of all the elements between the \(x-th\) and the \(y-th\) ones (inclusively, counting from \(1\)) in the sequence.

Input

Multiple test cases, please proceed them one by one. Input terminates by EOF.

For each test case:

The first line contains an integer \(n\). The following line contains \(n\) integers, representing the sequence \(a_1 \ldots a_n\).

The third line contains an integer \(m\). The next \(m\) lines contain the operations in the form i x y.\(i = 0\) denotes the modify operation,\(i = 1\) denotes the query operation.

Output

For each test case:

Output the case number (counting from \(1\)) in the first line of output. Then for each query, print an integer as the problem required.

Print an blank line after each test case.

See the sample output for more details.

Sample Input

5
1 2 3 4 5
5
1 2 4
0 2 4
1 2 4
0 4 5
1 1 5
4
10 10 10 10
3
1 1 4
0 2 3
1 1 4

Sample Output

Case #1:
9
4
6

Case #2:
40
26

Data Range

All test data are guaranteed that:\(n \leq 100000, m \leq 100000\).

Explanation

任何一个在 \(10^{18}\) 以内的数字, 只要最多对自己进行 \(8\) 次根号操作就会变成 \(1\), 并且根号操作不具有区间可合并性, 所以我们需要暴力地进行修改, 不暴力地进行区间查询. 时间复杂度为 \(\beta(n) \cdot n \log n\), 其中 \(\beta(n)\) 为不停进行运算 \(\left\lfloor\sqrt{x}\right\rfloor\) 得到 \(1\) 需要的次数, 在给定数据范围内满足 \(\beta(n) \leq 8\), 可以视作常数.

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>

using namespace std;
typedef long long lli;
const int maxn = 100100;

class SegmentTree
{
public:
    struct node
    {
        node *lc, *rc;
        int lb, mb, rb;
        lli sum;
    } *root, npool[maxn<<1];
    int n, ncnt;
    node* make_node(void)
    {
        node *p = &npool[++ncnt];
        p->lc = p->rc = NULL;
        p->lb = p->mb = p->rb = 0;
        p->sum = 0;
        return p;
    }
    lli query(node *p, int l, int r)
    {
        if (p->lb == l && p->rb == r) {
            return p->sum;
        }
        if (r <= p->mb) {
            return query(p->lc, l, r);
        } else if (l > p->mb) {
            return query(p->rc, l, r);
        } else {
            return query(p->lc, l, p->mb) +
                query(p->rc, p->mb + 1, r);
        }
        return lli();
    }
    lli query(int l, int r)
    {
        if (l > r) swap(l, r);
        return this->query(root, l, r);
    }
    void change(node *p, int l, int r)
    {
        if (p->lb == l && p->rb == r) {
            if (p->rb - p->lb + 1 == p->sum)
                return ;
            if (p->lb == p->rb) {
                p->sum = sqrt(p->sum);
                return ;
            }
            change(p->lc, l, p->mb);
            change(p->rc, p->mb + 1, r);
            p->sum = p->lc->sum + p->rc->sum;
            return ;
        }
        if (r <= p->mb) {
            change(p->lc, l, r);
        } else if (l > p->mb) {
            change(p->rc, l, r);
        } else {
            change(p->lc, l, p->mb);
            change(p->rc, p->mb + 1, r);
        }
        p->sum = p->lc->sum + p->rc->sum;
        return ;
    }
    void change(int l, int r)
    {
        if (l > r) swap(l, r);
        this->change(root, l, r);
        return ;
    }
    node* build_tree(int l, int r, lli arr[])
    {
        node *p = make_node();
        int mid = (l + r) >> 1;
        p->lb = l; p->mb = mid; p->rb = r;
        if (p->lb == p->rb) {
            p->sum = lli(arr[mid]);
        } else {
            p->lc = build_tree(l, mid, arr);
            p->rc = build_tree(mid + 1, r, arr);
            p->sum = p->lc->sum + p->rc->sum;
        }
        return p;
    }
    void build(int n, lli arr[])
    {
        this->ncnt = 0;
        this->n = n;
        this->root = this->build_tree(1, n, arr);
        return ;
    }
} st;

int n, m;
lli arr[maxn];

int main(int argc, char** argv)
{
    int case_id = 0;
    while (scanf("%d", &n) != EOF) {
        case_id += 1;
        if (n == 0)
            break;
        for (int i = 1; i <= n; i++)
            scanf("%lld", &arr[i]);
        st.build(n, arr);
        // Can you answer these queries
        scanf("%d", &m);
        printf("Case #%d:\n", case_id);
        for (int i = 1, x, l, r; i <= m; i++) {
            scanf("%d%d%d", &x, &l, &r);
            if (x == 1) {
                lli res = st.query(l, r);
                printf("%lld\n", res);
            } else if (x == 0) {
                st.change(l, r);
            }
        }
        printf("\n");
    }
    return 0;
}