1. 程式人生 > >4927 線段樹練習5 (多重標記下放)

4927 線段樹練習5 (多重標記下放)

題目 def void can scan tput 表示 urn div

題目描述 Description

有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]的最小值

輸入描述 Input Description

第一行兩個整數n,m,第二行n個整數表示這n個數的初始值

接下來m行操作,同題目描述

輸出描述 Output Description

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

樣例輸入 Sample Input

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

樣例輸出 Sample Output

49

11

4

數據範圍及提示 Data Size & Hint

10%:1<n,m<=10

30%:1<n,m<=10000

100%:1<n,m<=100000

保證中間結果在long long(C/C++)、int64(pascal)範圍內

思路;

有兩個標記一個add一個set,我們肯定是優先處理set操作,如果當前點被set標記了,那麽之前的add標記也會被清空,所以當進行set操作是必須要清空add標記。

題目沒給 c 的範圍,那麽我們假定他為 -1e9 < c < 1e9 ,那麽也就是有可能存在等於0和負數的情況,所以set標記的初始化可以選定為 -1e16;

為社麽感覺寫過。。。

實現代碼;

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid ll m = (l + r) >> 1
const ll M = 1e5 + 10
; const ll inf = 1e16+10; ll sum[M<<2],Set[M<<2],mx[M<<2],add[M<<2],mn[M<<2]; ll a[M]; void pushup(ll rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]; mx[rt] = max(mx[rt<<1],mx[rt<<1|1]); mn[rt] = min(mn[rt<<1],mn[rt<<1|1]); } void pushdown(ll l,ll r,ll rt){ if(Set[rt]!=-inf){ mid; sum[rt<<1] = Set[rt]*(m-l+1); sum[rt<<1|1] = Set[rt]*(r-m); mx[rt<<1] = mx[rt<<1|1] = Set[rt]; mn[rt<<1] = mn[rt<<1|1] = Set[rt]; Set[rt<<1] = Set[rt<<1|1] = Set[rt]; add[rt<<1] = add[rt<<1|1] = 0; Set[rt] = -inf; } if(add[rt]){ mid; sum[rt<<1] += add[rt]*(m-l+1); sum[rt<<1|1] += add[rt]*(r-m); mx[rt<<1] += add[rt]; mx[rt<<1|1] += add[rt]; mn[rt<<1] += add[rt]; mn[rt<<1|1] += add[rt]; add[rt<<1] += add[rt]; add[rt<<1|1] += add[rt]; add[rt] = 0; } } void build(ll l,ll r,ll rt){ Set[rt] = -inf; add[rt] = 0; if(l == r){ sum[rt] = mx[rt] = mn[rt] = a[l]; Set[rt] = -inf;add[rt] = 0; return ; } mid; build(lson); build(rson); pushup(rt); } void update(ll L,ll R,ll op,ll c,ll l,ll r,ll rt){ if(L <= l&&R >= r){ if(op == 1){ sum[rt] = (r-l+1)*c; mx[rt] = mn[rt] = Set[rt] = c; add[rt] = 0; return ; } else{ sum[rt] += (r-l+1)*c; mx[rt] += c; add[rt] += c; mn[rt] += c; return ; } } pushdown(l,r,rt); mid; if(L <= m) update(L,R,op,c,lson); if(R > m) update(L,R,op,c,rson); pushup(rt); } ll query_sum(ll L,ll R,ll l,ll r,ll rt){ if(L <= l&&R >= r){ return sum[rt]; } pushdown(l,r,rt); mid; ll ret = 0; if(L <= m) ret += query_sum(L,R,lson); if(R > m) ret += query_sum(L,R,rson); return ret; } ll query_max(ll L,ll R,ll l,ll r,ll rt){ if(L <= l&&R >= r){ return mx[rt]; } pushdown(l,r,rt); mid; ll ret = -inf; if(L <= m) ret = max(ret,query_max(L,R,lson)); if(R > m) ret = max(ret,query_max(L,R,rson)); return ret; } ll query_min(ll L,ll R,ll l,ll r,ll rt){ if(L <= l&&R >= r){ return mn[rt]; } pushdown(l,r,rt); mid,ret = inf; if(L <= m) ret = min(ret,query_min(L,R,lson)); if(R > m) ret = min(ret,query_min(L,R,rson)); return ret; } char s[100]; int main(){ ll n,l,r,c,q; scanf("%lld%lld",&n,&q); for(ll i = 1;i <= n;i ++) scanf("%lld",&a[i]); build(1,n,1); while(q--){ scanf("%s",s); scanf("%lld%lld",&l,&r); if(s[0] == a){ scanf("%lld",&c); update(l,r,0,c,1,n,1); } else if(s[0] == s&&s[1] == e){ scanf("%lld",&c); update(l,r,1,c,1,n,1); } else if(s[0] == s&&s[1] == u){ printf("%lld\n",query_sum(l,r,1,n,1)); } else if(s[0] == m&&s[1] == a){ printf("%lld\n",query_max(l,r,1,n,1)); } else { printf("%lld\n",query_min(l,r,1,n,1)); } } return 0; }

4927 線段樹練習5 (多重標記下放)