bzoj4364 [IOI2014]wall砖墙 线段树

90 篇文章 0 订阅

Description


给定一个长度为n的序列,要求资瓷

  1. 把l到r的数字与v取max
  2. 把l到r的数字与v取min

输出最后结果
对于100%的数据,1≤n≤2,000,000,1≤k≤500,000。

Solution


一开始想找一道最假女选手这样的题写一写的。。
我们可以直接上线段树beats!维护最大值、次大值、最小值、次小值,就是不太好写
实际上我们可以开两棵线段树分别维护区间的上界和下界,最终遍历一次就可以了

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

const int INF=0x3f3f3f3f;
const int N=2000005;

int mx[N<<2],mn[N<<2],tgx[N<<2],tgn[N<<2];

int read() {
	int x=0,v=1; char ch=getchar();
	for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
	for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
	return x*v;
}

void push_up(int now) {
	mx[now]=std:: max(mx[now<<1],mx[now<<1|1]);
	mn[now]=std:: min(mn[now<<1],mn[now<<1|1]);
}

void cmax(int &x,int v) {
	(x<v)?(x=v):0;
}

void cmin(int &x,int v) {
	(x>v)?(x=v):0;
}

void updx(int now,int w) {
	cmax(tgx[now],w); cmax(tgn[now],w);
	cmax(mx[now],w); cmax(mn[now],w);
}

void updn(int now,int w) {
	cmin(tgx[now],w); cmin(tgn[now],w);
	cmin(mx[now],w); cmin(mn[now],w);
}

void push_down(int now) {
	if (tgx[now]!=-INF) {
		int w=tgx[now]; tgx[now]=-INF;
		updx(now<<1,w); updx(now<<1|1,w);
	}
	if (tgn[now]!=INF) {
		int w=tgn[now]; tgn[now]=INF;
		updn(now<<1,w); updn(now<<1|1,w);
	}
}

void mMax(int now,int tl,int tr,int l,int r,int v) {
	if (r<l) return ;
	if (tl>=l&&tr<=r) {
		updx(now,v); return ;
	}
	push_down(now);
	int mid=(tl+tr)>>1;
	mMax(now<<1,tl,mid,l,std:: min(r,mid),v);
	mMax(now<<1|1,mid+1,tr,std:: max(mid+1,l),r,v);
	push_up(now);
}

void mMin(int now,int tl,int tr,int l,int r,int v) {
	if (r<l) return ;
	if (tl>=l&&tr<=r) {
		updn(now,v); return ;
	}
	push_down(now);
	int mid=(tl+tr)>>1;
	mMin(now<<1,tl,mid,l,std:: min(r,mid),v);
	mMin(now<<1|1,mid+1,tr,std:: max(mid+1,l),r,v);
	push_up(now);
}

void build(int now,int tl,int tr) {
	tgx[now]=-INF; tgn[now]=INF;
	if (tl==tr) return ;
	int mid=(tl+tr)>>1;
	build(now<<1,tl,mid);
	build(now<<1|1,mid+1,tr);
}

void ouput(int now,int tl,int tr) {
	if (tl==tr) return (void) (printf("%d\n", mx[now]));
	push_down(now);
	int mid=(tl+tr)>>1;
	ouput(now<<1,tl,mid); ouput(now<<1|1,mid+1,tr);
	push_up(now);
}

int main(void) {
	int n=read(),m=read();
	build(1,1,n);
	for (;m--;) {
		int opt=read(),l=read()+1,r=read()+1,k=read();
		if (opt==1) mMax(1,1,n,l,r,k);
		else mMin(1,1,n,l,r,k);
	}
	ouput(1,1,n);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值