[BZOJ3211][SPOJ2713][線段樹]GSS 4(花神遊歷各國)[一般題]

題幹

維護一個區間,支持兩種操作:

  1. 區間求和;
  2. 區間開平方(將一個區間內的數全部開平方)。

當然在BZOJ上這道題被加上了奇奇怪怪的背景……

  • 區間長度不超過100,000;
  • 操作個數不超過200,000;
  • 區間內的數不超過1,000,000,000。

題解

最重要的性質:一個1,000,000,000以內的數最多開方7次就會變成1。

所以:預處理每個區間內的數開n次方的和(0 <= n <= 7),進行優化。

(不要隨便看代碼。不要隨便看代碼。不要隨便看代碼。因爲很重要所以說三遍。)

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
using namespace std;

//Global Variables & Definitions
typedef long long LL;

int N, M;
int data[100010];
//End Global Variables & Definitions

//Segment Tree
struct Tree {
    int l, r;
    LL sum[7];
    LL s;
    int ptr;

    int lazy;
} T[400040];

inline LL Sum(int u) {
    return ~T[u].ptr ? T[u].sum[T[u].ptr] : T[u].s;
}

void PushUp(int u) {
    if(T[u << 1].ptr == T[u << 1 | 1].ptr && ~T[u << 1].ptr) {
        T[u].ptr = T[u << 1].ptr;
    } else {
        T[u].ptr = -1;
        T[u].s = Sum(u << 1) + Sum(u << 1 | 1);
    }
}

inline void MakeLazy(int u, int v) {
    T[u].ptr = T[u].ptr + v; if(T[u].ptr > 6) T[u].ptr = 6;
    T[u].lazy = T[u].lazy + v; if(T[u].lazy > 6) T[u].lazy = 6;

}

void PushDown(int u) {
    if(!T[u].lazy) return;
    MakeLazy(u << 1, T[u].lazy);
    MakeLazy(u << 1 | 1, T[u].lazy);
    PushUp(u);
    T[u].lazy = 0;
}

void Build(int u, int l, int r) {
    T[u].l = l; T[u].r = r;
    T[u].ptr = 0; T[u].lazy = 0;

    if(l == r) { 
        LL *sum = T[u].sum;

        sum[0] = data[l];
        for(int i = 1;i < 7;++i) sum[i] = (int)(sqrt(sum[i - 1]));

        return;
    }

    int mid = (l + r) >> 1;
    Build(u << 1, l, mid);
    Build(u << 1 | 1, mid + 1, r);

    for(int i = 0;i < 7;++i) T[u].sum[i] = T[u << 1].sum[i] + T[u << 1 | 1].sum[i];
    PushUp(u);
}

LL Query(int u, int l, int r) {
    if(l <= T[u].l && r >= T[u].r) return Sum(u);
    PushDown(u);

    int mid = (T[u].l + T[u].r) >> 1;
    LL ans = 0ll;
    if(l <= mid) ans += Query(u << 1, l, r);
    if(r > mid) ans += Query(u << 1 | 1, l, r);
    return ans;
}

void Update(int u, int l, int r) {
    if(l <= T[u].l && r >= T[u].r && ~T[u].ptr) { MakeLazy(u, 1); return; }
    PushDown(u);

    int mid = (T[u].l + T[u].r) >> 1;
    if(l <= mid) Update(u << 1, l, r);
    if(r > mid) Update(u << 1 | 1, l ,r);

    PushUp(u);
}
//End Segment Tree

//Main Structure
inline void ir() {
    scanf("%d", &N);
    for(int i = 1;i <= N;++i) scanf("%d", &data[i]);
    Build(1, 1, N);
}

int main() {
    ir();

    int x, l, r;
    scanf("%d", &M);
    for(int i = 0;i < M;++i) {
        scanf("%d%d%d", &x, &l, &r);

        if(x == 1) {
            printf("%lld\n", Query(1, l, r));
        } else {
            Update(1, l, r);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章