hdu4819

链接:点击打开链接

题意:给出一个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;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值