链接:点击打开链接
题意:给出一个N*N的矩阵,然后给出x,y,l三个数,找出以x,y为中心边长为l的正方形矩阵中的最大值和最小值,并将最大值和最小值的平均值赋给(x,y),并输出每次(x,y)的值
代码:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <algorithm>
using namespace std;
const int SIZE=805;
const int INF=0x3f3f3f3f;
int n,X1,Y1,X2,Y2,val,maxx,minx; //因为同时需要最大值和最小值,所以建两颗数
int s[SIZE][SIZE],MAX[SIZE<<2][SIZE<<2],MIN[SIZE<<2][SIZE<<2];
void buildy(int x,int l,int r,int rtx,int rty){
int m;
if(l==r){
if(x!=-1) //如果是树叶则直接赋值
MAX[rtx][rty]=MIN[rtx][rty]=s[x][l];
else{ //不是则在根据当前节点的左节点和右节点所建的树的相同位置的值更新当前节点的树的值......
MAX[rtx][rty]=max(MAX[rtx<<1][rty],MAX[rtx<<1|1][rty]);
MIN[rtx][rty]=min(MIN[rtx<<1][rty],MIN[rtx<<1|1][rty]);
}
return;
}
m=(l+r)>>1;
buildy(x,l,m,rtx,rty<<1);
buildy(x,m+1,r,rtx,rty<<1|1); //正常继续建树,然后pushup
MAX[rtx][rty]=max(MAX[rtx][rty<<1],MAX[rtx][rty<<1|1]);
MIN[rtx][rty]=min(MIN[rtx][rty<<1],MIN[rtx][rty<<1|1]);
}
void buildx(int l,int r,int rtx){
int m;
if(l==r){
buildy(l,1,n,rtx,1); //找到X的区间后转到Y的区间,参数x设为1
return;
}
m=(l+r)>>1;
buildx(l,m,rtx<<1);
buildx(m+1,r,rtx<<1|1);
buildy(-1,1,n,rtx,1); //不是树叶的节点所表示的区间
}
void updatey(int x,int l,int r,int rtx,int rty){
int m;
if(l==r){
if(x!=-1)
MAX[rtx][rty]=MIN[rtx][rty]=val;
else{
MAX[rtx][rty]=max(MAX[rtx<<1][rty],MAX[rtx<<1|1][rty]);
MIN[rtx][rty]=min(MIN[rtx<<1][rty],MIN[rtx<<1|1][rty]);
}
return;
}
m=(l+r)>>1;
if(Y1<=m)
updatey(x,l,m,rtx,rty<<1);
if(Y1>m)
updatey(x,m+1,r,rtx,rty<<1|1);
MAX[rtx][rty]=max(MAX[rtx][rty<<1],MAX[rtx][rty<<1|1]);
MIN[rtx][rty]=min(MIN[rtx][rty<<1],MIN[rtx][rty<<1|1]);
}
void updatex(int l,int r,int rtx){
int m;
if(l==r){
updatey(l,1,n,rtx,1);
return;
}
m=(l+r)>>1;
if(X1<=m)
updatex(l,m,rtx<<1);
if(X1>m)
updatex(m+1,r,rtx<<1|1);
updatey(-1,1,n,rtx,1);
}
void query_y(int l,int r,int rtx,int rty){
int m;
if(Y1<=l&&r<=Y2){
maxx=max(maxx,MAX[rtx][rty]);
minx=min(minx,MIN[rtx][rty]);
return;
}
m=(l+r)>>1;
if(Y1<=m)
query_y(l,m,rtx,rty<<1);
if(Y2>m)
query_y(m+1,r,rtx,rty<<1|1);
}
void query_x(int l,int r,int rtx){
int m;
if(X1<=l&&r<=X2){
query_y(1,n,rtx,1);
return;
}
m=(l+r)>>1;
if(X1<=m)
query_x(l,m,rtx<<1);
if(X2>m)
query_x(m+1,r,rtx<<1|1);
} //询问和更新就是其实都是基本线段树的思想,与一维线段
int main(){ //树的差异就是先找X区间再找Y区间,然后注意参数x的使用
int t,k,m,i,j,x,y,l; //判断是不是树叶
k=1;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&s[i][j]);
buildx(1,n,1);
scanf("%d",&m);
printf("Case #%d:\n",k++);
while(m--){
scanf("%d%d%d",&x,&y,&l);
X1=max(1,x-(l-1)/2),X2=min(n,x+(l-1)/2);
Y1=max(1,y-(l-1)/2),Y2=min(n,y+(l-1)/2);
maxx=-INF,minx=INF; //找坐标满足条件的范围
query_x(1,n,1);
val=(maxx+minx)/2;
X1=x,Y1=y;
printf("%d\n",val);
updatex(1,n,1);
}
}
return 0;
}