CPU監控
歷史最大值可以讓我們想到吉司機,然後發現這裡有個就要考慮區間推平和區間加對lazytag的影響。我們要維護6個tag,maxx,hmaxx,ha,a,hc,c。考慮之前的線段樹對於區間覆蓋和區間加之怎麼做的。我們發現如果我們有一個c標記,那麼如果我們要下傳一個ad標記,那麼我們可以讓c加上ad。如果我們要下傳一個c標記那我們就覆蓋c標記。考慮推廣到吉司機上。發現有四種情況(視作一開始就有ad標記,且值為0,所以不會有沒ad的情況)
重點程式碼:
void push_up(long long p){
d[p].maxx=max(d[p<<1].maxx,d[p<<1|1].maxx);
d[p].hmaxx=max(d[p<<1].hmaxx,d[p<<1|1].hmaxx);
}
void update(long long ad,long long had,long long c,long long hc,long long p){
if(d[p].c!=-1e16){
d[p].hc=max(d[p].hc,d[p].c+had);
d[p].c+=ad;
}else{
d[p].had=max(d[p].had,d[p].ad+had);
d[p].ad+=ad;
}
d[p].hmaxx=max(d[p].hmaxx,d[p].maxx+had);
d[p].maxx+=ad;
if(c!=-1e16){
if(d[p].c!=-1e16){
d[p].hc=max(d[p].hc,hc);
d[p].c=c;
}else{
d[p].hc=hc;
d[p].c=c;
}
d[p].maxx=c;
d[p].hmaxx=max(d[p].hmaxx,hc);
}
}
void push_down(long long p){
update(d[p].ad,d[p].had,d[p].c,d[p].hc,p<<1);
update(d[p].ad,d[p].had,d[p].c,d[p].hc,p<<1|1);
d[p].c=d[p].hc=-1e16;
d[p].ad=d[p].had=0;
}
void update_ad(long long l,long long r,long long p,long long s,long long t,long long ad){
if(l>=s&&r<=t){
if(d[p].c!=-1e16){
d[p].hc=max(d[p].hc,d[p].c+ad);
d[p].c+=ad;
}else{
d[p].had=max(d[p].had,d[p].ad+ad);
d[p].ad+=ad;
}
d[p].hmaxx=max(d[p].hmaxx,d[p].maxx+ad);
d[p].maxx+=ad;
return;
}
long long mid=(l+r)>>1;
push_down(p);
if(s<=mid) update_ad(l,mid,p<<1,s,t,ad);
if(t>mid) update_ad(mid+1,r,p<<1|1,s,t,ad);
push_up(p);
}
void update_c(long long l,long long r,long long p,long long s,long long t,long long c){
if(l>=s&&r<=t){
if(d[p].c!=-1e16){
d[p].hc=max(d[p].hc,c);
d[p].c=c;
}else{
d[p].hc=c;
d[p].c=c;
}
d[p].maxx=c;
d[p].hmaxx=max(d[p].hmaxx,c);
return;
}
long long mid=(l+r)>>1;
push_down(p);
if(s<=mid) update_c(l,mid,p<<1,s,t,c);
if(t>mid) update_c(mid+1,r,p<<1|1,s,t,c);
push_up(p);
}
線段樹 3
沒有2的操作上面講過了,然後考慮區間推平怎麼做。我們可以維護一個maxx,se,mx_ad,ad,cnt然後還有普通的sum,hmx_ad,had,hmaxx然後區間推平時如果這個區間只有一種數大於推平的數,那麼就操作,否則就遞迴下去。因為這個只有ad標記,上面都講過了
void push_up(long long p){//好理解
d[p].sum=d[p<<1].sum+d[p<<1|1].sum;
d[p].maxx=max(d[p<<1].maxx,d[p<<1|1].maxx);
d[p].hmaxx=max(d[p<<1].hmaxx,d[p<<1|1].hmaxx);
if(d[p<<1].maxx==d[p<<1|1].maxx){
d[p].se=max(d[p<<1].se,d[p<<1|1].se);
d[p].cnt=d[p<<1].cnt+d[p<<1|1].cnt;
}else if(d[p<<1].maxx>d[p<<1|1].maxx){
d[p].se=max(d[p<<1|1].maxx,d[p<<1].se);
d[p].cnt=d[p<<1].cnt;
}else if(d[p<<1].maxx<d[p<<1|1].maxx){
d[p].se=max(d[p<<1].maxx,d[p<<1|1].se);
d[p].cnt=d[p<<1|1].cnt;
}
}
void update(long long mx_ad,long long mx_had,long long ad,long long had,long long p){//順序,se的id(好理解)
d[p].sum+=(ad*(d[p].r-d[p].l+1-d[p].cnt)+mx_ad*d[p].cnt);
d[p].hmaxx=max(d[p].maxx+mx_had,d[p].hmaxx);
d[p].maxx+=mx_ad;
if(d[p].se!=1e16) d[p].se+=ad;
d[p].mx_had=max(d[p].mx_had,mx_had+d[p].mx_ad);
d[p].had=max(d[p].had,had+d[p].ad);
d[p].ad+=ad;
d[p].mx_ad+=mx_ad;
}
void push_down(long long p){
int maxx=max(d[p<<1].maxx,d[p<<1|1].maxx);//這裡要臨時存一下,不然會變
if(maxx==d[p<<1].maxx) update(d[p].mx_ad,d[p].mx_had,d[p].ad,d[p].had,p<<1);//下傳的是對應的la,是maxx傳maxx,否則傳次大值的
else update(d[p].ad,d[p].had,d[p].ad,d[p].had,p<<1);
if(maxx==d[p<<1|1].maxx) update(d[p].mx_ad,d[p].mx_had,d[p].ad,d[p].had,p<<1|1);
else update(d[p].ad,d[p].had,d[p].ad,d[p].had,p<<1|1);
d[p].mx_had=d[p].mx_ad=d[p].had=d[p].ad=0;
}
void update_ad(long long l,long long r,long long p,long long s,long long t,long long ad){
if(l>=s&&r<=t){
d[p].sum+=ad*(d[p].r-d[p].l+1);
d[p].hmaxx=max(d[p].maxx+ad,d[p].hmaxx);
d[p].maxx+=ad;
if(d[p].se!=1e16) d[p].se+=ad;
d[p].mx_had=max(d[p].mx_had,d[p].mx_ad+ad);
d[p].had=max(d[p].had,d[p].ad+ad);
d[p].ad+=ad;
d[p].mx_ad+=ad;
return;
}
long long mid=(l+r)>>1;
push_down(p);
if(s<=mid) update_ad(l,mid,p<<1,s,t,ad);
if(t>mid) update_ad(mid+1,r,p<<1|1,s,t,ad);
push_up(p);
}
void update_min(long long l,long long r,long long p,long long s,long long t,long long ad){
if(ad>=d[p].maxx) return;
if(l>=s&&r<=t&&ad>d[p].se){
d[p].sum-=d[p].cnt*(d[p].maxx-ad);
d[p].mx_ad-=(d[p].maxx-ad);
d[p].maxx=ad;
return;
}
long long mid=(l+r)>>1;
push_down(p);
if(s<=mid) update_min(l,mid,p<<1,s,t,ad);
if(t>mid) update_min(mid+1,r,p<<1|1,s,t,ad);
push_up(p);
}