HDU 4027 Can you answer these queries?

对区间进行操作:操作0是区间内的每个点的值val = int(sqrt(val)); 操作1是查询区间和。

题目链接

因为是区间操作,第一感觉是lazy,但是这题lazy在push_down的时候无法快速的对区间进行更新,所以变成点操作+剪枝。留意到每个点的值必然是正整数,且开根几次之后最终都会稳定在1,所以说一个节点表示的范围是[l,r]时,若sum[rt]=l-r+1,必然下面的每个节点都是1,不必再开根了。剪完这个枝就能过。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define mst(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(ll i=(a);i<(b);++i)
const double eps = 1e-8, PI = acos(-1.0f);
const int inf = 0x3f3f3f3f, maxN = 1e5 + 5;
int N, M, T;

// Segment tree
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define lch rt << 1
#define rch rt << 1 | 1

ll seg[maxN << 2];

void pushUp(int rt) { seg[rt] = seg[lch] + seg[rch]; }

void init(int l, int r, int rt) {
    if (l == r) {
        scanf("%lld", &seg[rt]);
        return;
    }
    int m = (l + r) >> 1;
    init(lson);
    init(rson);
    pushUp(rt);
}

void update(int L, int R, int l, int r, int rt) {
    if (l == r) {
        seg[rt] = sqrt(seg[rt]);
        return;
    }
    if (L <= l && r <= R && seg[rt] == r - l + 1)
        return;

    int m = (l + r) >> 1;
    if (L <= m) update(L, R, lson);
    if (R > m) update(L, R, rson);
    pushUp(rt);
}

ll query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) {
        return seg[rt];
    }
    int m = (l + r) >> 1;
    ll ans = 0;
    if (L <= m) ans += query(L, R, lson);
    if (R > m) ans += query(L, R, rson);
    return ans;
}


int main() {
#ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
#endif

    int cas = 1;
    while (~scanf("%d", &N)) {
        init(1, N, 1);
        scanf("%d", &M);
        int a, b, c;

        printf("Case #%d:
", cas++);
        rep(i, 0, M) {
            scanf("%d%d%d", &a, &b, &c);
            if (b > c) swap(b, c);
            if (a == 1)
                printf("%lld
", query(b, c, 1, N, 1));
            else
                update(b, c, 1, N, 1);
        }
        puts("");    
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Rosebud/p/9124897.html