[洛谷 P4314] CPU監控
阿新 • • 發佈:2021-08-24
一、題目
二、解法
第一次過歷史線段樹的題,寫篇題解紀念一下
核心思想就是將標記看作一個操作序列,我們需要額外維護一個序列字首最大值。
具體來說:我們維護 icv,cv,hcv
表示是否被覆蓋\(/\)當前的覆蓋標記\(/\)歷史覆蓋標記最大值;維護 ad,had
表示當前的加法標記\(/\)歷史加法標記最大值;維護 mx/hmx
表示區間最大值\(/\)歷史區間最大值。
關鍵之處:考慮如何下傳,因為在 \(cover\) 操作的時候我們要清空 \(ad\),那麼我們要先把加法標記先下傳,不能先下傳覆蓋標記是因為這樣會直接破壞兒子的加法標記。注意在操作序列出現 \(cover\) 之後,我們就不能直接進行加法操作了,因為這樣標記會混亂,但是我們能很容易的把加法操作等價轉化成覆蓋操作。
總結一句:對於歷史問題,想象一個操作序列來思考,要考慮操作之間的互相影響,可以把操作序列“分段”來解決這種影響,比如本題就是以 \(cover\) 操作來分段的(以後的操作就只用 \(cover\))。
#include <cstdio> #include <iostream> using namespace std; const int M = 100005; const int inf = -2147483648; int read() { int x=0,f=1;char c; while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;} while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();} return x*f; } int n,m;char s[10]; struct tree { int icv,hcv,cv,had,ad,mx,hmx; tree() {icv=hcv=cv=had=ad=0;mx=hmx=inf;} void cover(int d,int hd) { if(icv) hcv=max(hcv,hd); else hcv=hd,icv=1; mx=cv=d; hmx=max(hmx,hd); ad=0; } void Add(int d,int hd) { had=max(had,ad+hd); hmx=max(hmx,mx+hd); ad+=d;mx+=d; } void add(int d,int hd) { if(icv) cover(cv+d,cv+hd); else Add(d,hd); } }tr[4*M]; void down(int i) { //download the add tag tr[i<<1].add(tr[i].ad,tr[i].had); tr[i<<1|1].add(tr[i].ad,tr[i].had); tr[i].ad=tr[i].had=0; //download the covering tag if(tr[i].icv) { tr[i<<1].cover(tr[i].cv,tr[i].hcv); tr[i<<1|1].cover(tr[i].cv,tr[i].hcv); tr[i].icv=tr[i].hcv=tr[i].cv=0; } } void up(int i) { tr[i].mx=max(tr[i<<1].mx,tr[i<<1|1].mx); tr[i].hmx=max(tr[i].hmx,tr[i].mx); } void cov(int i,int l,int r,int L,int R,int x) { if(l>R || L>r) return ; if(L<=l && r<=R) { tr[i].cover(x,x); return ; } int mid=(l+r)>>1;down(i); cov(i<<1,l,mid,L,R,x); cov(i<<1|1,mid+1,r,L,R,x); up(i); } void add(int i,int l,int r,int L,int R,int x) { if(l>R || L>r) return ; if(L<=l && r<=R) { tr[i].add(x,x); return ; } int mid=(l+r)>>1;down(i); add(i<<1,l,mid,L,R,x); add(i<<1|1,mid+1,r,L,R,x); up(i); } int ask(int i,int l,int r,int L,int R) { if(L>r || l>R) return inf; if(L<=l && r<=R) return tr[i].mx; int mid=(l+r)>>1;down(i); return max(ask(i<<1,l,mid,L,R), ask(i<<1|1,mid+1,r,L,R)); } int hask(int i,int l,int r,int L,int R) { if(L>r || l>R) return inf; if(L<=l && r<=R) return tr[i].hmx; int mid=(l+r)>>1;down(i); return max(hask(i<<1,l,mid,L,R), hask(i<<1|1,mid+1,r,L,R)); } void build(int i,int l,int r) { if(l==r) { tr[i].mx=tr[i].hmx=read(); return ; } int mid=(l+r)>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r); up(i); } signed main() { n=read();build(1,1,n); m=read(); while(m--) { scanf("%s",s);int l=read(),r=read(); if(s[0]=='Q') printf("%d\n",ask(1,1,n,l,r)); if(s[0]=='A') printf("%d\n",hask(1,1,n,l,r)); if(s[0]=='P') add(1,1,n,l,r,read()); if(s[0]=='C') cov(1,1,n,l,r,read()); } }