[IOI2014]Wall 砖墙 线段树

原题: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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值