HDU4819:Mosaic(二维线段树简单模板,树套树,单独修改,区间查询)

题目链接

题意:

给定一个N*N的矩阵,每个格子都有一个数,再给出Q个询问,每次询问以(x,y)为中心的边长为L(L必为奇数)的正方形矩阵中的最大值和最小值,并修改(x,y)的值为(MAX+MIN)/2。


树套树。以x建线段树,每个x区间中又有一个全区间的y线段树。

在这里插入图片描述


里面还是有一些细节的:
1、全局变量的利用。
2、buildy和updatey函数中有个变量k,分别用作 记录x的位置,判断当前区间是否在判读区间内。总体是用作标记。
3、单独修改,区间查询,所以没有pushdown函数。如果有区间修改,就得适合的加pushdown函数,看情况吧。
4、复杂度O(log ^ 2)。
5、还有一种 四叉树 的做法,题解链接。不推荐用。


部分代码:

#define ls		i<<1
#define rs		i<<1|1
#define mid		((l+r)>>1)
#define lson	ls,l,mid
#define rson	rs,mid+1,r
const int maxn=800+7;
int T,n,Q,a[maxn][maxn],xl,xr,yl,yr,t,p,q;
int mx[maxn<<2][maxn<<2],mi[maxn<<2][maxn<<2];
void pushupx(int i,int j){
	mx[i][j]=max(mx[ls][j],mx[rs][j]);
	mi[i][j]=min(mi[ls][j],mi[rs][j]);
}
void pushupy(int i,int j){
	mx[i][j]=max(mx[i][j<<1],mx[i][j<<1|1]);
	mi[i][j]=min(mi[i][j<<1],mi[i][j<<1|1]);
}
void buildy(int x,int i,int l,int r,int k){
	if(l==r){
		if(k)	mx[x][i]=mi[x][i]=a[k][r];
		else	pushupx(x,i);
		return;
	}
	buildy(x,lson,k);	buildy(x,rson,k);
	pushupy(x,i);
}
void buildx(int i,int l,int r){
	if(l==r){
		buildy(i,1,1,n,r);
		return;
	}
	buildx(lson);	buildx(rson);
	buildy(i,1,1,n,0);
}
void updatey(int x,int i,int l,int r,int k){
	if(l>yr||r<yl)	return;
	if(yl<=l&&r<=yr){
		if(k)	mx[x][i]=mi[x][i]=t;
		else	pushupx(x,i);
		return;
	}
	updatey(x,lson,k);	updatey(x,rson,k);
	pushupy(x,i);
}
void updatex(int i,int l,int r){
	if(l>xr||r<xl)	return;
	if(xl<=l&&r<=xr){
		updatey(i,1,1,n,r);
		return;
	}
	updatex(lson);	updatex(rson);
	updatey(i,1,1,n,0);
}
void queryy(int x,int i,int l,int r){
	if(l>yr||r<yl)	return;
	if(yl<=l&&r<=yr){
		p=max(p,mx[x][i]);
		q=min(q,mi[x][i]);
		return;
	}
	queryy(x,lson);	queryy(x,rson);
}
void queryx(int i,int l,int r){
	if(l>xr||r<xl)	return;
	if(xl<=l&&r<=xr){
		queryy(i,1,1,n);
		return;
	}
	queryx(lson);	queryx(rson);
}
int main(){
	T=read();
	for(int v=1;v<=T;v++){
		n=read();	int x,y,l;
		for(int i=1;i<=n;i++)	for(int j=1;j<=n;j++)	a[i][j]=read();
		buildx(1,1,n);
		Q=read();	printf("Case #%d:\n",v);
		while(Q--){
			x=read();	y=read();	l=read();
			l>>=1;	p=0;	q=1e9+7;
			xl=max(1,x-l);	yl=max(1,y-l);
			xr=min(n,x+l);	yr=min(n,y+l);
			queryx(1,1,n);	t=(p+q)>>1;
			xl=xr=x;	yl=yr=y;
			updatex(1,1,n);
			printf("%d\n",t);
		}
	}
}

另一种写法

关于这种单点修改、区间查询、二维线段树的题,还有一种写法模板:hdu 4819 Mosaic

他的这种写法也可以借鉴,虽然不是我的代码风格,但也要有注意的。

1、树套树,一般可以写在结构体中。(之后我有篇博客会整理。)这种结构体中的函数套另一个结构体的函数,很方便。

2、他的Modify函数,用的是线段树中的 非递归实现 ,可以说他用线段树很熟练了,其它也可以转换为非递归实现,因为这题只是单点修改。区间修改的话,非递归实现比较难写。

3、如果他这种可以用全局变量来记录查询区间的最大/小值,这代码还可以更短。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值