原题:https://www.luogu.org/problemnew/show/P4560
题解:两个操作,添加操作[l,r]将所有数的改大于等于h的,已经大的就不用改了,删除操作将所有数都保持在小于等于h的(已经小的就不用改了)。考虑用线段树维护两种标记,mm表示下界,mn表示上界。相当于答案就在mm-mn,显然mm<=mn,所以mm的初值就是0,mn的初值就是inf
而mm就是答案。开始讨论:
首先考虑添加操作,h表示添加到的数,x表示该区间的mm,y表示该区间的mn
若 h<=x 则不用操作,
若x<h<y 需要将 x改成h
若h>=y 需要将y改成h
所以可以得出添加操作时对mm,mn的影响是mm=max(mm,h),mn=max(mn,h)
删除操作也同理,mm=min(mm,h) mn=min(mn,h)
区间标记下放时也一样,相当于对左右子树进行添加和删除操作。
#include<bits/stdc++.h>
#define mid (l+r)/2
#define ls now<<1
#define rs now<<1|1
using namespace std;
const int N=2200000;
int mm[N<<2],mn[N<<2];
int n,m,inf;
inline int rd(){
int x=0;int f=1;char s=getchar();
while(!isdigit(s)) f=(s=='-'?-1:f),s=getchar();
while(isdigit(s))x=(x<<1)+(x<<3)+s-'0',s=getchar();
return x*f;
}
void pushdown(int now){
if(mm[now]!=0){
int x=mm[now];mm[now]=0;
mm[ls]=max(mm[ls],x);
mn[ls]=max(mn[ls],x);
mm[rs]=max(mm[rs],x);
mn[rs]=max(mn[rs],x);
}
if(mn[now]!=inf){
int x=mn[now];mn[now]=inf;
mm[ls]=min(mm[ls],x);
mn[ls]=min(mn[ls],x);
mm[rs]=min(mm[rs],x);
mn[rs]=min(mn[rs],x);
}
}
void change(int now,int l,int r,int x,int y,int h,int opt){
if(x<=l && r<=y){
if(opt==1) {
mm[now]=max(mm[now],h);
mn[now]=max(mn[now],h);
}
if(opt==2) {
mm[now]=min(mm[now],h);
mn[now]=min(mn[now],h);
}
return ;
}
pushdown(now);
if(x<=mid) change(ls,l,mid,x,y,h,opt);
if(mid<y) change(rs,mid+1,r,x,y,h,opt);
}
void print(int now,int l,int r){
if(l==r) {
printf("%d\n",mm[now]);return;
}
pushdown(now);
print(ls,l,mid);
print(rs,mid+1,r);
}
int main(){
// freopen("wall.in","r",stdin);
n=rd(); m=rd();
memset(mn,0x3f,sizeof mn);inf=mn[0];
memset(mm,0,sizeof mm);
for(int i=1,opt,l,r,h;i<=m;i++){
opt=rd();l=rd()+1;r=rd()+1;h=rd();
change(1,1,n,l,r,h,opt);
}
print(1,1,n);
return 0;
}