【hdu5306】Gorgeous Sequence 線段樹區間最值操作
阿新 • • 發佈:2018-01-19
font 區間和 pro while turn lin int ace 退出
否則,無法直接計算貢獻,遞歸子樹處理。
題目描述
給你一個序列,支持三種操作:
$0\ x\ y\ t$ :將 $[x,y]$ 內大於 $t$ 的數變為 $t$ ;
$1\ x\ y$ :求 $[x,y]$ 內所有數的最大值;
$2\ x\ y$ :求 $[x,y]$ 內所有數的和。
多組測試數據,$\sum n,\sum m\le 10^6$
題解
線段樹區間最值操作
對於線段樹上的一個節點,維護對應區間的:最大值 $mx$ 、最大值個數 $c$ 及嚴格次大值 $se$ 。那麽對於一次區間最小值操作:
如果 $t\ge mx$ ,則這個操作不會對區間產生影響,直接退出;
如果 $se<t<mx$ ,則這個操作只會對區間最大值產生影響,區間和減小 $c(mx-t)$ ,最大值變為 $t$ ,打標記退出;
其中第二種情況的 “打標記” 實際上就是下傳新的最大值,因此可以不打標記,直接將最大值下傳。
這樣做的時間復雜度是 $O(n\log n)$ 的,證明參考 吉老師的Segment tree Beats!
#include <cstdio> #include <algorithm> #define N 1000010 #define lson l , mid , x << 1 #define rson mid + 1 , r , x << 1 | 1 using namespace std; typedef long long ll; ll mx[N << 2] , c[N << 2] , se[N << 2] , sum[N << 2]; inline void vmin(ll v , int x) { if(mx[x] > v) sum[x] -= c[x] * (mx[x] - v) , mx[x] = v; } inline void pushup(int x) { int l = x << 1 , r = x << 1 | 1; sum[x] = sum[l] + sum[r]; if(mx[l] > mx[r]) mx[x] = mx[l] , c[x] = c[l] , se[x] = max(se[l] , mx[r]); if(mx[l] < mx[r]) mx[x] = mx[r] , c[x] = c[r] , se[x] = max(mx[l] , se[r]); if(mx[l] == mx[r]) mx[x] = mx[l] , c[x] = c[l] + c[r] , se[x] = max(se[l] , se[r]); } inline void pushdown(int x) { vmin(mx[x] , x << 1) , vmin(mx[x] , x << 1 | 1); } void build(int l , int r , int x) { if(l == r) { scanf("%lld" , &mx[x]) , sum[x] = mx[x] , c[x] = 1 , se[x] = -1; return; } int mid = (l + r) >> 1; build(lson) , build(rson); pushup(x); } void update(int b , int e , ll v , int l , int r , int x) { if(mx[x] <= v) return; if(b <= l && r <= e && se[x] < v) { vmin(v , x); return; } pushdown(x); int mid = (l + r) >> 1; if(b <= mid) update(b , e , v , lson); if(e > mid) update(b , e , v , rson); pushup(x); } ll qmax(int b , int e , int l , int r , int x) { if(b <= l && r <= e) return mx[x]; pushdown(x); int mid = (l + r) >> 1; ll ans = 0; if(b <= mid) ans = max(ans , qmax(b , e , lson)); if(e > mid) ans = max(ans , qmax(b , e , rson)); return ans; } ll qsum(int b , int e , int l , int r , int x) { if(b <= l && r <= e) return sum[x]; pushdown(x); int mid = (l + r) >> 1; ll ans = 0; if(b <= mid) ans += qsum(b , e , lson); if(e > mid) ans += qsum(b , e , rson); return ans; } int main() { int T; scanf("%d" , &T); while(T -- ) { int n , m , opt , x , y; ll z; scanf("%d%d" , &n , &m); build(1 , n , 1); while(m -- ) { scanf("%d%d%d" , &opt , &x , &y); if(opt == 0) scanf("%lld" , &z) , update(x , y , z , 1 , n , 1); if(opt == 1) printf("%lld\n" , qmax(x , y , 1 , n , 1)); if(opt == 2) printf("%lld\n" , qsum(x , y , 1 , n , 1)); } } return 0; }
【hdu5306】Gorgeous Sequence 線段樹區間最值操作