封面来源
Pixiv 春を告げる-94945362
题意:一颗线段树,可以维护区间加,区间取最值(),区间求和(,区间最大值,区间历史最值
吉老师提出了这样的解决方案:对于每一个节点,维护区间最大值,和最大值出现次数,区间严格次大值。在区间取操作时遍历线段树,直到,由于我们维护了区间最大值和次数,所以维护其他信息也就容易了。
修改经典线段树如下:
1.pushup
cpp
inline void pushup(int p){
nd[p].mxa=max(nd[lc].mxa,nd[rc].mxa);
nd[p].mxb=max(nd[lc].mxb,nd[rc].mxb);
nd[p].sum=nd[lc].sum+nd[rc].sum;
if(nd[lc].mxa==nd[rc].mxa){
nd[p].sec=max(nd[lc].sec,nd[rc].sec);
nd[p].cnt=nd[lc].cnt+nd[rc].cnt;
}
else if(nd[lc].mxa>nd[rc].mxa){
nd[p].sec=max(nd[lc].sec,nd[rc].mxa);
nd[p].cnt=nd[lc].cnt;
}
else{
nd[p].sec=max(nd[lc].mxa,nd[rc].sec);
nd[p].cnt=nd[rc].cnt;
}
}
2.pushdown
感谢@Watertomato的讲解,维护四个 tag,,
表示当前区间最大值的 lazy_tag和非最大值的 lazy_tag,
同理,表示当前区间最大值的历史上加的最多的那次标记和非最大值的 历史上加的最多的那次标记
cpp
inline void pushdown(int p){
int maxx=max(nd[lc].mxa,nd[rc].mxa);
if(nd[lc].mxa==maxx)
upd(lc,nd[p].add_a,nd[p].add_b,nd[p].add_a1,nd[p].add_b1);
else upd(lc,nd[p].add_a1,nd[p].add_b1,nd[p].add_a1,nd[p].add_b1);
if(nd[rc].mxa==maxx)
upd(rc,nd[p].add_a,nd[p].add_b,nd[p].add_a1,nd[p].add_b1);
else upd(rc,nd[p].add_a1,nd[p].add_b1,nd[p].add_a1,nd[p].add_b1);
nd[p].add_a=nd[p].add_b=nd[p].add_a1=nd[p].add_b1=0;
}
3.update
cpp
inline void upd(int p,int k1,int k2,int k3,int k4){
nd[p].sum+=k1*nd[p].cnt+k3*(nd[p].len-nd[p].cnt);
nd[p].mxb=max(nd[p].mxb,nd[p].mxa+k2);
nd[p].add_b=max(nd[p].add_b,nd[p].add_a+k2);
nd[p].add_b1=max(nd[p].add_b1,nd[p].add_a1+k4);
nd[p].mxa+=k1;
nd[p].add_a+=k1;
nd[p].add_a1+=k3;
if(nd[p].sec!=-inf){
nd[p].sec+=k3;
}
}
表示当前/历史最大值要加的数。
表示非最大值要加的数。
4.update_min
cpp
inline void update_min(int p,int l,int r,int x,int y,int k){
if(l>y||r<x||k>nd[p].mxa)return;
if(l>=x&&r<=y&&k>=nd[p].sec){
upd(p,k-nd[p].mxa,k-nd[p].mxa,0,0);
return;
}
pushdown(p);
update_min(lc,l,mid,x,y,k);
update_min(rc,mid+1,r,x,y,k);
pushup(p);
}
其他的和一般线段树没有区别了,直接看代码实现吧
cpp
#include<bits/stdc++.h>
#define inf 0x7fffffffffffff
#define FOR(i,l,r) for(register int i=l;i<=r;i++)
#define mid ((l+r)>>1)
#define lc p<<1
#define rc p<<1|1
#define int long long
using namespace std;
const int N = 501000;int n,m;
struct STN{//segement nd node
int add_a,add_a1,add_b,add_b1;
int mxa,sec,mxb,sum,cnt,len;
}nd[N<<3];
inline int read();
int a[N];
inline void pushup(int);//
inline void build(int,int,int);//
inline void pushdown(int);//
inline void upd(int,int,int,int,int);//
inline void update_add(int,int,int,int,int,int);//
inline void update_min(int,int,int,int,int,int);//
inline int Qsum(int,int,int,int,int);//
inline int Qmxa(int,int,int,int,int);//
inline int Qmxb(int,int,int,int,int);//
signed main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif
n=read(),m=read();
FOR(i,1,n){
a[i]=read();
}
build(1,1,n);
for(int i=1,op,l,r,k;i<=m;i++){
op=read();
l=read();
r=read();
if(op==1){
k=read();
update_add(1,1,n,l,r,k);
}
else if(op==2){
k=read();
update_min(1,1,n,l,r,k);
}
else if(op==3){
printf("%lld\n",Qsum(1,1,n,l,r));
}
else if(op==4){
printf("%lld\n",Qmxa(1,1,n,l,r));
}
else if(op==5){
printf("%lld\n",Qmxb(1,1,n,l,r));
}
}
}
inline int read() {
int r=0;bool w=0; char ch=getchar();
while(ch<'0'||ch>'9') w=ch=='-'?1:0,ch=getchar();
while(ch>='0'&&ch<='9') r=r*10+(ch^48), ch=getchar();
return w?-r:r;
}
inline void pushup(int p){
nd[p].mxa=max(nd[lc].mxa,nd[rc].mxa);
nd[p].mxb=max(nd[lc].mxb,nd[rc].mxb);
nd[p].sum=nd[lc].sum+nd[rc].sum;
if(nd[lc].mxa==nd[rc].mxa){
nd[p].sec=max(nd[lc].sec,nd[rc].sec);
nd[p].cnt=nd[lc].cnt+nd[rc].cnt;
}
else if(nd[lc].mxa>nd[rc].mxa){
nd[p].sec=max(nd[lc].sec,nd[rc].mxa);
nd[p].cnt=nd[lc].cnt;
}
else{
nd[p].sec=max(nd[lc].mxa,nd[rc].sec);
nd[p].cnt=nd[rc].cnt;
}
}
inline void build(int p,int l,int r){
nd[p].len=r-l+1;
if(l==r){
nd[p].mxa=nd[p].mxb=nd[p].sum=a[l];
nd[p].sec=-inf;
nd[p].cnt=1;
return;
}
build(lc,l,mid);
build(rc,mid+1,r);
pushup(p);
}
inline void pushdown(int p){
int maxx=max(nd[lc].mxa,nd[rc].mxa);
if(nd[lc].mxa==maxx)
upd(lc,nd[p].add_a,nd[p].add_b,nd[p].add_a1,nd[p].add_b1);
else upd(lc,nd[p].add_a1,nd[p].add_b1,nd[p].add_a1,nd[p].add_b1);
if(nd[rc].mxa==maxx)
upd(rc,nd[p].add_a,nd[p].add_b,nd[p].add_a1,nd[p].add_b1);
else upd(rc,nd[p].add_a1,nd[p].add_b1,nd[p].add_a1,nd[p].add_b1);
nd[p].add_a=nd[p].add_b=nd[p].add_a1=nd[p].add_b1=0;
}
inline void upd(int p,int k1,int k2,int k3,int k4){
nd[p].sum+=k1*nd[p].cnt+k3*(nd[p].len-nd[p].cnt);
nd[p].mxb=max(nd[p].mxb,nd[p].mxa+k2);
nd[p].add_b=max(nd[p].add_b,nd[p].add_a+k2);
nd[p].add_b1=max(nd[p].add_b1,nd[p].add_a1+k4);
nd[p].mxa+=k1;
nd[p].add_a+=k1;
nd[p].add_a1+=k3;
if(nd[p].sec!=-inf){
nd[p].sec+=k3;
}
}
inline void update_add(int p,int l,int r,int x,int y,int k){
if(l>y||r<x)return;
if(l>=x&&r<=y){
upd(p,k,k,k,k);
return;
}
pushdown(p);
update_add(lc,l,mid,x,y,k);
update_add(rc,mid+1,r,x,y,k);
pushup(p);
}
inline void update_min(int p,int l,int r,int x,int y,int k){
if(l>y||r<x||k>nd[p].mxa)return;
if(l>=x&&r<=y&&k>=nd[p].sec){
upd(p,k-nd[p].mxa,k-nd[p].mxa,0,0);
return;
}
pushdown(p);
update_min(lc,l,mid,x,y,k);
update_min(rc,mid+1,r,x,y,k);
pushup(p);
}
inline int Qsum(int p,int l,int r,int x,int y){
if(l>y||r<x)return 0;
if(l>=x&&r<=y){
return nd[p].sum;
}
pushdown(p);
return Qsum(lc,l,mid,x,y)+Qsum(rc,mid+1,r,x,y);
}
inline int Qmxa(int p,int l,int r,int x,int y){
if(l>y||r<x)return -inf;
if(l>=x&&r<=y){
return nd[p].mxa;
}
pushdown(p);
return max(Qmxa(lc,l,mid,x,y),Qmxa(rc,mid+1,r,x,y));
}
inline int Qmxb(int p,int l,int r,int L,int R){
if(l>R||r<L) return -1e18;
if(l>=L&&r<=R) return nd[p].mxb;
pushdown(p);
return max(Qmxb(lc,l,mid,L,R),Qmxb(rc,mid+1,r,L,R));
}
后记
其实这篇文章完全可以算是搬运的。。。但好歹还是调了我一天的一道题,就当留个纪念吧.
参考资料
