HDU4027

Description

大意是要求实现一个可以给区间每个数开根,同时区间求和的线段树。

思路

由于开根后求和不等于求和后开根,所以每次更新都必须更新到根节点。所幸开根一个数到1之后再开根结果不变,所以如果发现某个线段的和等于r-l+1说明无需再更新。
由于开根操作是指数级别,每个区间被更新的最大次数不会很大,所以不会超时。
这题的输入似乎不保证l<=r,以后只要题目没提到l<=r就处理一下,防止出错。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
#include <cmath>

using namespace std;
#define endl '
'
typedef long long ll;
const int N = 200000;

ll sum[N << 2];
ll lazy[N << 2];

void pushup(int rt) {
    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}

void pushdown(int rt) {
    lazy[rt << 1] += lazy[rt]; 
    lazy[rt << 1 | 1] += lazy[rt];
    lazy[rt] = 0;
}

void update(int l, int r, int L, int R, int rt) {
    if(L <= l && R >= r) {
        lazy[rt]++;
    } else {
        int mid = (l + r) / 2;
        pushdown(rt);
        if(L <= mid) update(l, mid, L, R, rt << 1);
        if(R > mid) update(mid + 1, r, L, R, rt << 1 | 1);
        pushup(rt);
    }
}

ll query(int l, int r, int L, int R, int rt) {
    
    ll res = 0;
    if(L <= l && R >= r) {
        if(sum[rt] == r - l + 1) return sum[rt];
    }
    if(l == r) {
        int ti = lazy[rt];
        while(ti--) {
            sum[rt] = (ll)sqrt(sum[rt]);
        } 
        lazy[rt] = 0;
        return sum[rt];
    }
    pushdown(rt);
    int mid = (l + r) / 2;
    if(L <= mid) res += query(l, mid, L, R, rt << 1);
    if(R > mid) res += query(mid + 1, r, L, R, rt << 1 | 1);
    pushup(rt);
    return res;
}

void build(int l, int r, int rt) {
    if(l == r) {
        cin >> sum[rt];
        lazy[rt] = 0;
    } else {
        lazy[rt] = 0;
        int mid = (l + r) / 2;
        build(l, mid, rt << 1);
        build(mid + 1, r, rt << 1 | 1);
        pushup(rt);
    }
}

int main() {
    ios::sync_with_stdio(false);
    int cases = 1;
    int n;
    while(cin >> n) {
        cout << "Case #" << cases << ":" << endl;
        build(1, n, 1);
        int m;
        cin >> m;
        while(m--) {
            int t;
            int l, r;
            cin >> t >> l >> r;
            if(l > r) swap(l ,r);
            if(t) {
                cout << query(1, n, l, r, 1) << endl;
            } else {
                update(1, n, l, r, 1);
            }
        }
        cout << endl;
        cases++;
    }
}

原文地址:https://www.cnblogs.com/limil/p/12741605.html