[codevs4927] 線段樹練習5(線段樹)

題目

描述

有n個數和5種操作
add a b c:把區間[a,b]內的所有數都增加c
set a b c:把區間[a,b]內的所有數都設爲c
sum a b:查詢區間[a,b]的區間和
max a b:查詢區間[a,b]的最大值
min a b:查詢區間[a,b]的最小值

輸入

第一行兩個整數n,m,第二行n個整數表示這n個數的初始值
接下來m行操作,同題目描述

輸出

對於所有的sum、max、min詢問,一行輸出一個答案

樣例輸入

10 6
3 9 2 8 1 7 5 0 4 6
add 4 9 4
set 2 6 2
add 3 8 2
sum 2 10
max 1 7
min 3 6

樣例輸出

49
11
4

數據範圍及提示

10%: 1<n,m10
30%: 1<n,m10000
100%: 1<n,m100000
保證中間結果在long long(C/C++)、int64(pascal)範圍內

解題思路

線段樹中每個節點有兩個標記:set和add,分別表示重置和區間加。定義一個節點同時存在兩個標記時,先下放set標記,再下放加標記,那麼當我們進行重置操作時,只需要將當前節點的加標記清零即可。

Code

#include<cstdio>
#include<algorithm>

#define lid id<<1
#define rid id<<1|1
#define mid ((tr[id].l+tr[id].r)>>1)
#define len(id) (tr[id].r-tr[id].l+1)

using namespace std;

typedef long long LL;

const LL INF = 1e17;
const int N = 100005;
int n, m, ql, qr;
LL a[N], x;
char opt[4];

struct seg_tree{
    int l, r;
    LL sum, mx, mn;
    LL set, add;
    void init(){
        l = r = 0;
        sum = 0, mx = -INF, mn = INF;
        add = 0, set = INF;
    }
}tr[N<<2];

inline void pushup(int id){
    tr[id].sum = tr[lid].sum + tr[rid].sum;
    tr[id].mx = max(tr[lid].mx, tr[rid].mx);
    tr[id].mn = min(tr[lid].mn, tr[rid].mn);
}

inline void pushdown(int id){
    if(tr[id].l == tr[id].r)    return;
    if(tr[id].set != INF){
        LL t = tr[id].set;
        tr[lid].set = t;
        tr[lid].add = 0;
        tr[lid].sum = t * len(lid);
        tr[lid].mx = tr[lid].mn = t;
        tr[rid].set = t;
        tr[rid].add = 0;
        tr[rid].sum = t * len(rid);
        tr[rid].mx = tr[rid].mn = t;
        tr[id].set = INF;
    }
    if(tr[id].add){
        LL t = tr[id].add;
        tr[lid].add += t;
        tr[lid].sum += t * len(lid);
        tr[lid].mx += t;
        tr[lid].mn += t;
        tr[rid].add += t;
        tr[rid].sum += t * len(rid);
        tr[rid].mx += t;
        tr[rid].mn += t;
        tr[id].add = 0;
    }
}

void build(int id, int l, int r){
    tr[id].init();
    tr[id].l = l, tr[id].r = r;
    if(tr[id].l == tr[id].r){
        tr[id].sum = tr[id].mx = tr[id].mn = a[l];
        return;
    }
    build(lid, l, mid);
    build(rid, mid+1, r);
    pushup(id);
}

void modify(int id, int l, int r, LL val, int kind){
    pushdown(id);
    if(tr[id].l == l && tr[id].r == r){
        if(kind == 0){
            tr[id].add += val;
            tr[id].sum += val * len(id);
            tr[id].mx += val, tr[id].mn += val;
        }
        else{
            tr[id].set = val;
            tr[id].add = 0;
            tr[id].sum = val * len(id);
            tr[id].mx = tr[id].mn = val;
        }
        return;
    }
    if(r <= mid)    modify(lid, l, r, val, kind);
    else if(l > mid)    modify(rid, l, r, val, kind);
    else    modify(lid, l, mid, val, kind), modify(rid, mid+1, r, val, kind);
    pushup(id);
}

LL query(int id, int l, int r, int kind){
    pushdown(id);
    if(tr[id].l == l && tr[id].r == r){
        if(kind == 0)   return tr[id].sum;
        if(kind == 1)   return tr[id].mx;
        if(kind == 2)   return tr[id].mn;
    }
    if(r <= mid)    return query(lid, l, r, kind);
    else if(l > mid)    return query(rid, l, r, kind);
    else{
        if(kind == 0)   return query(lid, l, mid, kind) + query(rid, mid+1, r, kind);
        if(kind == 1)   return max(query(lid, l, mid, kind), query(rid, mid+1, r, kind));
        if(kind == 2)   return min(query(lid, l, mid, kind), query(rid, mid+1, r, kind));
    }
}

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    build(1, 1, n);
    while(m--){
        scanf("%s%d%d", opt, &ql, &qr);
        if(opt[0] == 'a'){
            scanf("%lld", &x);
            modify(1, ql, qr, x, 0);
        }
        else if(opt[1] == 'e'){
            scanf("%lld", &x);
            modify(1, ql, qr, x, 1);
        }
        else if(opt[0] == 's')
            printf("%lld\n", query(1, ql, qr, 0));
        else if(opt[1] == 'a')
            printf("%lld\n", query(1, ql, qr, 1));
        else if(opt[1] == 'i')
            printf("%lld\n", query(1, ql, qr, 2));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章