#树套树,二维线段树#HDU 4819 Mosaic

题目

多组数据,给定一个\(n*n\)的矩阵(\(n\leq 80,a_{i,j}\leq 10^9\))

多组询问一个以\((x,y)\)为中心,边长为\(L\)的子矩阵最大值\(mx\)和最小值\(mn\),

并将\((x,y)\)这一个位置修改为\(\lfloor\frac{mn+mx}{2}\rfloor\),每次询问输出修改后的\((x,y)\)


分析

二维线段树裸题,反正之前也没敲过,

其实和一维线段树相近,找到\(lx\sim rx\)的下标

再按照一维线段树的方式修改最大最小值就可以了


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=801,M=3201; struct rec{int x,y;};
int wmn[M][M],wmx[M][M],ans,n,a[N][N];
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline signed min(int a,int b){return a<b?a:b;}
inline signed max(int a,int b){return a>b?a:b;}
inline void pupx(int kx,int ky){
	wmn[kx][ky]=min(wmn[kx<<1][ky],wmn[kx<<1|1][ky]);
	wmx[kx][ky]=max(wmx[kx<<1][ky],wmx[kx<<1|1][ky]);
}
inline void pupy(int kx,int ky){
	wmn[kx][ky]=min(wmn[kx][ky<<1],wmn[kx][ky<<1|1]);
	wmx[kx][ky]=max(wmx[kx][ky<<1],wmx[kx][ky<<1|1]);
}
inline void buildy(int ky,int kx,int l,int r,int z){
	if (l==r){
		if (z) wmn[kx][ky]=wmx[kx][ky]=a[z][l];
		    else pupx(kx,ky);
		return;
	}
	rr int mid=(l+r)>>1;
	buildy(ky<<1,kx,l,mid,z);
	buildy(ky<<1|1,kx,mid+1,r,z);
	pupy(kx,ky);
}
inline void buildx(int k,int l,int r){
	if (l==r){
		buildy(1,k,1,n,l);
		return;
	}
	rr int mid=(l+r)>>1;
	buildx(k<<1,l,mid);
	buildx(k<<1|1,mid+1,r);
	buildy(1,k,1,n,0);
}
inline void updatey(rec K,int l,int r,rec t,int z){
	if (l==t.x&&r==t.y){
		if (z) wmn[K.x][K.y]=wmx[K.x][K.y]=ans;
		    else pupx(K.x,K.y);
		return;
	}
	rr int mid=(l+r)>>1;
	if (t.y<=mid) updatey((rec){K.x,K.y<<1},l,mid,t,z);
	    else if (t.x>mid) updatey((rec){K.x,K.y<<1|1},mid+1,r,t,z);
	        else {
	        	updatey((rec){K.x,K.y<<1},l,mid,(rec){t.x,mid},z);
	        	updatey((rec){K.x,K.y<<1|1},mid+1,r,(rec){mid+1,t.y},z);
			}
	pupy(K.x,K.y);
}
inline void updatex(int k,int l,int r,rec L,rec R){
	if (l==L.x&&r==L.y){
		updatey((rec){k,1},1,n,R,1);
		return;
	}
	rr int mid=(l+r)>>1;
	if (L.y<=mid) updatex(k<<1,l,mid,L,R);
	    else if (L.x>mid) updatex(k<<1|1,mid+1,r,L,R);
	        else {
	        	updatex(k<<1,l,mid,(rec){L.x,mid},R);
	        	updatex(k<<1|1,mid+1,r,(rec){mid+1,L.y},R);
			}
	updatey((rec){k,1},1,n,R,0);
}
inline void queryy(rec K,int l,int r,rec t,int &mn,int &mx){
	if (l==t.x&&r==t.y){
		mn=min(mn,wmn[K.x][K.y]),
		mx=max(mx,wmx[K.x][K.y]);
		return;
	}
	rr int mid=(l+r)>>1;
    if (t.y<=mid) queryy((rec){K.x,K.y<<1},l,mid,t,mn,mx);
        else if (t.x>mid) queryy((rec){K.x,K.y<<1|1},mid+1,r,t,mn,mx);
            else {
            	queryy((rec){K.x,K.y<<1},l,mid,(rec){t.x,mid},mn,mx);
            	queryy((rec){K.x,K.y<<1|1},mid+1,r,(rec){mid+1,t.y},mn,mx);
			}
}
inline void queryx(int k,int l,int r,rec L,rec R,int &mn,int &mx){
	if (l==L.x&&r==L.y){
		queryy((rec){k,1},1,n,R,mn,mx);
		return;
	}
	rr int mid=(l+r)>>1;
	if (L.y<=mid) queryx(k<<1,l,mid,L,R,mn,mx);
	    else if (L.x>mid) queryx(k<<1|1,mid+1,r,L,R,mn,mx);
	        else {
	        	queryx(k<<1,l,mid,(rec){L.x,mid},R,mn,mx);
	        	queryx(k<<1|1,mid+1,r,(rec){mid+1,L.y},R,mn,mx);
			}
}
signed main(){
	for (rr int Test=iut(),T=1;T<=Test;++T){
		printf("Case #%d:\n",T),n=iut();
		for (rr int i=1;i<=n;++i)
		for (rr int j=1;j<=n;++j) a[i][j]=iut();
		buildx(1,1,n);
		for (rr int Q=iut();Q;--Q){
			rr int x=iut(),y=iut(),L=(iut()-1)>>1;
			rr int lx=max(x-L,1),ly=max(y-L,1),mx=0;
			rr int rx=min(x+L,n),ry=min(y+L,n),mn=1e9;
			queryx(1,1,n,(rec){lx,rx},(rec){ly,ry},mn,mx),
			ans=(mx+mn)>>1,lx=rx=x,ly=ry=y;
			print(ans),putchar(10),
			updatex(1,1,n,(rec){lx,rx},(rec){ly,ry});
		}
	}
	return 0;
}

原文地址:https://www.cnblogs.com/Spare-No-Effort/p/12549372.html

时间: 2024-08-07 23:40:39

#树套树,二维线段树#HDU 4819 Mosaic的相关文章

POJ 2155 二维线段树

POJ 2155  二维线段树 思路:二维线段树就是每个节点套一棵线段树的树. 刚开始因为题目是求A[I,J],然后在y查询那直接ans^=Map[i][j]的时候没看懂,后面自己把图画出来了才理解. 因为只有0和1,所以可以用异或来搞,而不需要每次都需要修改. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #incl

HDU 4819 Mosaic --二维线段树(树套树)

题意: 给一个矩阵,每次查询一个子矩阵内的最大最小值,然后更新子矩阵中心点为(Max+Min)/2. 解法: 由于是矩阵,且要求区间最大最小和更新单点,很容易想到二维的线段树,可是因为之前没写过二维的线段树,所以没跳出来.后来熟悉了一下,原来很多细节地方都没有考虑到. 这里build,update,query都分为两个函数,第一个为Y轴的(sub_update),第二个为X轴的(update),不仅每个sub_update或sub_build后面要加Y轴的pushup函数,而且每个update或

HDU 1823 Luck and Love 二维线段树(树套树)

点击打开链接 Luck and Love Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5460    Accepted Submission(s): 1364 Problem Description 世界上上最远的距离不是相隔天涯海角 而是我在你面前 可你却不知道我爱你 ―― 张小娴 前段日子,枫冰叶子给Wiskey做了个征婚启事

HDU 1823 二维线段树(区间max)

Luck and Love Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5262    Accepted Submission(s): 1317 Problem Description 世界上上最远的距离不是相隔天涯海角而是我在你面前可你却不知道我爱你                ―― 张小娴 前段日子,枫冰叶子给Wiskey做了

hdu 4819 二维线段树模板

/* HDU 4819 Mosaic 题意:查询某个矩形内的最大最小值, 修改矩形内某点的值为该矩形(Mi+MA)/2; 二维线段树模板: 区间最值,单点更新. */ #include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 1010; int N, Q; struct Nodey { int l, r; int Max, Min; }; int locx[MAXN], l

Luck and Love (二维线段树)(树套树)

Luck and Love Problem Description 世界上上最远的距离不是相隔天涯海角 而是我在你面前 可你却不知道我爱你 ―― 李丹妮 前段日子,枫冰叶子给Wiskey做了个征婚启事,聘礼达到500万哦,天哪,可是天文数字了啊,不知多少MM蜂拥而至,顿时万人空巷,连扫地的大妈都来凑热闹来了.―_―||| 由于人数太多,Wiskey实在忙不过来,就把统计的事情全交给了枫冰叶子,自己跑回家休息去了.这可够枫冰叶子忙的了,他要处理的有两类事情,一是得接受MM的报名,二是要帮Wiske

HDU 1823 Luck and Love 二维线段树

Problem Description 世界上上最远的距离不是相隔天涯海角 而是我在你面前 可你却不知道我爱你 ―― 张小娴 前段日子,枫冰叶子给Wiskey做了个征婚启事,聘礼达到500万哦,天哪,可是天文数字了啊,不知多少MM蜂拥而至,顿时万人空巷,连扫地的大妈都来凑热闹来了.―_―||| 由于人数太多,Wiskey实在忙不过来,就把统计的事情全交给了枫冰叶子,自己跑回家休息去了.这可够枫冰叶子忙的了,他要处理的有两类事情,一是得接受MM的报名,二是要帮Wiskey查找符合要求的MM中缘分最

hdu 1823 Luck and Love ,二维线段树

Luck and Love Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5282    Accepted Submission(s): 1324 Input 本题有多个测试数据,第一个数字M,表示接下来有连续的M个操作,当M=0时处理中止. 接下来是一个操作符C. 当操作符为'I'时,表示有一个MM报名,后面接着一个整数,H表示身

[POJ2155] Matrix(二维线段树,树套树)

题目链接:http://poj.org/problem?id=2155 题意:给一个01矩阵,两个操作,翻转:子矩阵里每一个数都由0变1,1变0. 查询:查询某一点是0还是1. 一直以为二维线段树就是开一个线段树数组的我- 这题暴力更新每一个小矩形,翻转就+1,最后看看某点的奇偶. 写屎了,特别注意的是在外层查询的时候要先把当前层的内层query掉,接着再向下扩展.这样外层就不用lazy啦 1 #include <algorithm> 2 #include <iostream> 3