題目
描述
有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%:
30%:
100%:
保證中間結果在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;
}