[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章