HDU4819 Mosaic

本文详细解析了二维线段树的实现原理与应用,通过一个具体的问题实例,介绍了如何使用二维线段树来高效地处理矩阵中特定区间的最大值与最小值查询,并更新指定点的值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出一个n行n列的矩阵,每次询问一个二维区间,找出区间内最大值和最小值,去它们平均值,然后输出,再插入那个点。

也是裸裸的二维线段树,太渣。。写了好久,更新的那个地方出了问题,第一层树也要找到准确位置才更新,不是准确位置就从下面更新过的树维护上来。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls (k<<1)
#define rs (k<<1|1)
using namespace std;
const int MAXN=810;
const int INF=(1<<30)-1;
int mp[MAXN][MAXN];
struct Sub_Tree
{
	int l,r;
	int mxval,mival;
	int mid()
	{
		return (l+r)>>1;
	}
};
struct Tree
{
	int l,r;
	Sub_Tree stree[MAXN<<2];
	int mid()
	{
		return (l+r)>>1;
	}
}tree[MAXN<<2];
int n;
void pushup(int k,int fa)
{
	tree[fa].stree[k].mival=min(tree[fa].stree[ls].mival,tree[fa].stree[rs].mival);
	tree[fa].stree[k].mxval=max(tree[fa].stree[ls].mxval,tree[fa].stree[rs].mxval);
}
void pushupfa(int k,int fa)
{
	tree[fa].stree[k].mival=min(tree[fa<<1].stree[k].mival,tree[fa<<1|1].stree[k].mival);
	tree[fa].stree[k].mxval=max(tree[fa<<1].stree[k].mxval,tree[fa<<1|1].stree[k].mxval);
}
void build_sub(int l,int r,int k,int fa)
{
	tree[fa].stree[k].l=l;
	tree[fa].stree[k].r=r;
	tree[fa].stree[k].mival=INF;
	tree[fa].stree[k].mxval=-INF;
	if(l==r)
	{
		return;
	}
	int mid=tree[fa].stree[k].mid();
	build_sub(l,mid,ls,fa);
	build_sub(mid+1,r,rs,fa);
	pushup(k,fa);
}
void build(int l,int r,int k)
{
	tree[k].l=l;
	tree[k].r=r;
	build_sub(1,n,1,k);
	if(l==r)
		return;
	int mid=tree[k].mid();
	build(l,mid,ls);
	build(mid+1,r,rs);
}
void update_sub(int pos,int val,int k,int fa)
{
	if(tree[fa].stree[k].l==tree[fa].stree[k].r)
	{
		//printf("fa=%d pos=%d val=%d\n",fa,pos,val);
		if(tree[fa].l==tree[fa].r)	//第一层相同更新
			tree[fa].stree[k].mival=tree[fa].stree[k].mxval=val;
		else //第一层不同,从下面已经更新的区间维护上来
			pushupfa(k,fa);
		return;
	}
	int mid=tree[fa].stree[k].mid();
	if(pos<=mid)
		update_sub(pos,val,ls,fa);
	else
		update_sub(pos,val,rs,fa);
	pushup(k,fa);	//维护第二层数
}
void update(int pos1,int pos2,int val,int k)
{
	if(tree[k].l==tree[k].r)
	{
		update_sub(pos2,val,1,k);	//第一层树的左右区间相同,第一层也是一个要更新的点,更新第二层数的要更新的点的数值
		return;
	}
	int mid=tree[k].mid();
	if(pos1<=mid)
		update(pos1,pos2,val,ls);
	else
		update(pos1,pos2,val,rs);
	update_sub(pos2,val,1,k);	//第一层树的左右区间不同,从下面已经更新的第一层树维护上来
}
int query_submi(int l,int r,int k,int fa)
{
	if(tree[fa].stree[k].l>=l&&tree[fa].stree[k].r<=r)
	{
		//printf("mi:fa=%d l=%d r=%d val=%d\n",fa,tree[fa].stree[k].l,tree[fa].stree[k].r,tree[fa].stree[k].mival);
		return tree[fa].stree[k].mival;
	}
	int mid=tree[fa].stree[k].mid();
	if(r<=mid)
		return query_submi(l,r,ls,fa);
	else if(l>mid)
		return query_submi(l,r,rs,fa);
	else
	{
		int t1=query_submi(l,mid,ls,fa);
		int t2=query_submi(mid+1,r,rs,fa);
		return min(t1,t2);
	}
}
int querymi(int l,int r,int x,int y,int k)
{
	if(tree[k].l>=l&&tree[k].r<=r)
	{
		//printf("l=%d r=%d\n",tree[k].l,tree[k].r);
		return query_submi(x,y,1,k);
	}
	int mid=tree[k].mid();
	if(r<=mid)
		return querymi(l,r,x,y,ls);
	else if(l>mid)
		return querymi(l,r,x,y,rs);
	else
	{
		int t1=querymi(l,mid,x,y,ls);
		int t2=querymi(mid+1,r,x,y,rs);
		return min(t1,t2);
	}
}
int query_submx(int l,int r,int k,int fa)
{
	if(tree[fa].stree[k].l>=l&&tree[fa].stree[k].r<=r)
	{
		//printf("mx:fa=%d l=%d r=%d val=%d\n",fa,tree[fa].stree[k].l,tree[fa].stree[k].r,tree[fa].stree[k].mxval);
		return tree[fa].stree[k].mxval;
	}
	int mid=tree[fa].stree[k].mid();
	if(r<=mid)
		return query_submx(l,r,ls,fa);
	else if(l>mid)
		return query_submx(l,r,rs,fa);
	else
	{
		int t1=query_submx(l,mid,ls,fa);
		int t2=query_submx(mid+1,r,rs,fa);
		return max(t1,t2);
	}
}
int querymx(int l,int r,int x,int y,int k)
{
	if(tree[k].l>=l&&tree[k].r<=r)
	{
		//printf("l=%d r=%d\n",tree[k].l,tree[k].r);
		return query_submx(x,y,1,k);
	}
	int mid=tree[k].mid();
	if(r<=mid)
		return querymx(l,r,x,y,ls);
	else if(l>mid)
		return querymx(l,r,x,y,rs);
	else
	{
		int t1=querymx(l,mid,x,y,ls);
		int t2=querymx(mid+1,r,x,y,rs);
		return max(t1,t2);
	}
}
int main()
{
	int i,j,t,flag=1;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		build(1,n,1);
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=n;j++)
			{
				scanf("%d",&mp[i][j]);
				update(i,j,mp[i][j],1);
			}
		}
		int m,x,y,L;
		scanf("%d",&m);
		printf("Case #%d:\n",flag++);
		while(m--)
		{
			scanf("%d%d%d",&x,&y,&L);
			int l=x-L/2;
			int r=x+L/2;
			int a=y-L/2;
			int b=y+L/2;
			if(l<1)
				l=1;
			if(r>n)
				r=n;
			if(a<1)
				a=1;
			if(b>n)
				b=n;
			int ansmi=querymi(l,r,a,b,1);
			int ansmx=querymx(l,r,a,b,1);
			int ans=(ansmi+ansmx)/2;
			printf("%d\n",ans);
			update(x,y,ans,1);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值