4927 線段樹練習5 (多重標記下放)
阿新 • • 發佈:2018-11-03
題目 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 Input10 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 (多重標記下放)