洛谷P4145 上帝造题的七分钟2 / 花神游历各国 题解 线段树+懒惰标记

题目链接:https://www.luogu.com.cn/problem/P4145

题目大意:

两种操作:

  1. 区间求和;
  2. 区间开方。

解题思路:

使用线段树解决这个问题。

但是区间更新(开方)需要懒惰标记。

但是这样也会TLE,所以还需要记录区间更新的次数的最小值,如果这个区间内的每个数都开方达到6次,那么这个区间内的数就都是1了。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n, m;
long long sum[maxn<<2];
int lazy[maxn<<2], upd_times[maxn<<2];
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
void push_up(int rt) {
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    upd_times[rt] = min(upd_times[rt<<1], upd_times[rt<<1|1]);
}
void push_down(int rt, int l, int r) {
    if (lazy[rt]) {
        if (l < r) {
            lazy[rt<<1] += lazy[rt];
            lazy[rt<<1|1] += lazy[rt];
        }
        else {
            for (int i = 0; i < lazy[rt] && sum[rt] > 1; i ++)
                sum[rt] = sqrt(sum[rt]);
        }
        upd_times[rt] += lazy[rt];
    }
    lazy[rt] = 0;
}
void build(int l, int r, int rt) {
    if (l == r) {
        scanf("%lld", &sum[rt]);
    }
    else {
        int mid = (l + r) / 2;
        build(lson);
        build(rson);
        push_up(rt);
    }
}
void update(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) {
        lazy[rt] ++;
        return;
    }
    push_down(rt, l, r);
    if (upd_times[rt] > 6) return;
    int mid = (l + r) / 2;
    if (L <= mid) update(L, R, lson);
    if (R > mid) update(L, R, rson);
    push_up(rt);
}
long long query(int L, int R, int l, int r, int rt) {
    push_down(rt, l, r);
    if (L <= l && r <= R && upd_times[rt] > 6) return r-l+1;
    if (l == r) return sum[rt];
    long long tmp = 0;
    int mid = (l + r) / 2;
    if (L <= mid) tmp += query(L, R, lson);
    if (R > mid) tmp += query(L, R, rson);
    push_up(rt);
    return tmp;
}
int main() {
    scanf("%d", &n);
    build(1, n, 1);
    scanf("%d", &m);
    while (m --) {
        int op, l, r;
        scanf("%d%d%d", &op, &l, &r);
        if (l > r) swap(l, r);
        if (op == 0) {
            update(l, r, 1, n, 1);
        }
        else {
            printf("%lld
", query(l, r, 1, n, 1));
        }
    }
    return 0;
}