1. 程式人生 > >BZOJ.3064.CPU監控(線段樹 歷史最值)

BZOJ.3064.CPU監控(線段樹 歷史最值)

update -- 線段樹 git source sdi zoj == cst

題目鏈接
\(Description\)
有一個長為n的序列Ai,要求支持查詢[l,r]的最值、歷史最值,區間加/重設
\(Solution\)
線段樹,每個點再維護一個歷史(從0到現在)最大值、歷史(從上次下傳標記到現在)最大的set,add標記
PushDown時肯定是先下放歷史標記,之後再用當前標記更新

/*
要記得當要PushDown某個點時,last,now的val都是歷史的(下傳前),所以now.v + last.add就是下傳前值+[下傳前到現在]一次最大的修改的值 
不能只在Set後清空add。像代碼這麽做很正確,可以稍微畫個圖 
每次now的操作不僅要更新now,還要更新last 
*/ #include<cstdio> #include<cctype> #include<algorithm> #define gc() getchar() #define lson node[node[rt].ls] #define rson node[node[rt].rs] const int N=1e5+5,INF=0x3f3f3f3f; int n,m; inline int read() { int now=0,f=1;register char c=gc(); for(;!isdigit(c);c=gc()) if(c=='-'
) f=-1; for(;isdigit(c);now=now*10+c-'0',c=gc()); return now*f; } #define now node[rt] struct Seg_Tree { int tot; struct Node { int ls,rs,nv,lv,nadd,ladd,nset,lset; }node[N<<1]; inline void PushUp(int rt) { now.nv = std::max(lson.nv, rson.nv); now.lv = std::max(lson.lv, rson.lv); } void
Build(int l,int r) { int rt=tot++; now.nadd=now.ladd=0, now.nset=now.lset=-INF; if(l==r) now.nv=now.lv=read(); else { int m=l+r>>1; now.ls=tot, Build(l,m); now.rs=tot, Build(m+1,r); PushUp(rt); } } inline void Update(int &x,int y) {x = std::max(x,y);} inline void L_Set(int rt,int v) { Update(now.lv, v); Update(now.lset, v); } inline void L_Add(int rt,int v) { Update(now.lv, now.nv+v); if(now.nset>-INF) Update(now.lset, now.nset+v);//判斷的是nset>-INF(用now更新last關last什麽事)//necessary! else Update(now.ladd, now.nadd+v); //如果之後rt.ladd下傳了,那就沒了;如果沒下傳,仍是rt下傳前情況(歷史),即可以用now.ladd;或是用上次下傳前標記+到現在修改最大值 } inline void N_Set(int rt,int v) { Update(now.lv, now.nv=v); Update(now.lset, now.nset=v); now.nadd = 0; } inline void N_Add(int rt,int v) { Update(now.lv, now.nv+=v); if(now.nset>-INF) Update(now.lset, now.nset+=v); //Update的是lset,not ladd,現在更新的是set不是add//在被set影響後,所有操作都可看做set else Update(now.ladd, now.nadd+=v); } void PushDown(int rt) { if(now.ladd) L_Add(now.ls,now.ladd),L_Add(now.rs,now.ladd),now.ladd=0; if(now.lset>-INF) L_Set(now.ls,now.lset),L_Set(now.rs,now.lset),now.lset=-INF; if(now.nadd) N_Add(now.ls,now.nadd),N_Add(now.rs,now.nadd),now.nadd=0; if(now.nset>-INF) N_Set(now.ls,now.nset),N_Set(now.rs,now.nset),now.nset=-INF; } void Modify_Add(int l,int r,int rt,int L,int R,int v) { if(L<=l && r<=R) {N_Add(rt,v); return;} PushDown(rt); int m=l+r>>1; if(L<=m) Modify_Add(l,m,now.ls,L,R,v); if(m<R) Modify_Add(m+1,r,now.rs,L,R,v); PushUp(rt); } void Modify_Set(int l,int r,int rt,int L,int R,int v) { if(L<=l && r<=R) {N_Set(rt,v); return;} PushDown(rt); int m=l+r>>1; if(L<=m) Modify_Set(l,m,now.ls,L,R,v); if(m<R) Modify_Set(m+1,r,now.rs,L,R,v); PushUp(rt); } int Query(int l,int r,int rt,int L,int R,bool opt) { if(L<=l && r<=R) return opt?now.nv:now.lv; PushDown(rt); int m=l+r>>1; if(L<=m) if(m<R) return std::max(Query(l,m,now.ls,L,R,opt),Query(m+1,r,now.rs,L,R,opt)); else return Query(l,m,now.ls,L,R,opt); return Query(m+1,r,now.rs,L,R,opt); } }t; #undef now int main() { n=read(), t.Build(1,n), m=read(); char opt[3]; int x,y,z; while(m--) { scanf("%s",opt), x=read(),y=read(); switch(opt[0]) { case 'Q': printf("%d\n",t.Query(1,n,0,x,y,1)); break; case 'A': printf("%d\n",t.Query(1,n,0,x,y,0)); break; case 'P': z=read(), t.Modify_Add(1,n,0,x,y,z); break; case 'C': z=read(), t.Modify_Set(1,n,0,x,y,z); break; } } return 0; }

BZOJ.3064.CPU監控(線段樹 歷史最值)