二维线段树 四叉树

#include<cstdio>
#include<cstring>
#include<iostream>
#include "bits/stdc++.h"
#define LOGN 10
#define MAXN (1<<LOGN)
#define MAXNODES 3*( (1<<(2*LOGN)) / 4 + 100)
#define son(x) (p*4-2+x)//计算儿子公式
using namespace std;
int a[504][504];
struct dateinfo//信息
{
    short px,py;//点
    int val;//值
    void reset(int x){px=0,py=0,val=x;}
};
struct treenode//树上节点
{
    dateinfo maxi,mini;
    void reset(){maxi.reset(INT_MIN);mini.reset(INT_MAX);}
}nodes[MAXNODES];
treenode* getnode(int id){return &nodes[id];}
struct interval//区间类
{
    short l,r;
    short mid(){ return (l+r)>>1;}//区间中点
    short len(){ return (r-l+(short)1);}//区间长度
    interval left(){ return {l,mid()};}//左区间
    interval right(){ return {(short)(mid()+1) , r};}//右区间
    bool in(short x){ return x>=l&&x<=r;}//判点
    bool with(interval t){ return !((l>t.r)||(r<t.l));}//判交
    bool include(interval t){ return l<=t.l&&r>=t.r;}//判包含
};
bool build(int p,interval xl,interval yl)//bool判断是否存在该子节点
{
    if(xl.len()<=0||yl.len()<=0)return false;
    treenode* now = getnode(p);
    if(xl.len()==1&&yl.len()==1)
    {
        now->maxi={xl.l,xl.r,a[xl.l][yl.r]};
        now->mini={xl.l,xl.r,a[xl.l][yl.r]};
        return true;
    }
    now->reset();
    bool ok[4];
    ok[0]=build(son(0),xl.left(),yl.left());
    ok[1]=build(son(1),xl.right(),yl.left());
    ok[2]=build(son(2),xl.left(),yl.right());
    ok[3]=build(son(3),xl.right(),yl.right());
    for (int i = 0; i < 4; ++i) {//通过子节点更新now
        if(!ok[i])continue;
        treenode* son = getnode(son(i));
        now->maxi = son->maxi.val > now->maxi.val ? son->maxi : now->maxi;
        now->mini = son->mini.val < now->mini.val ? son->mini : now->mini;
    }
    return true;
}
bool update(int p,interval xl,interval yl,short px,short py,int val)
{
    if(xl.len()<=0||yl.len()<=0)return false;
    if(!xl.in(px) || !yl.in(py))return true;
    treenode* now = getnode(p);
    if(xl.len()==1&&yl.len()==1)
    {
        now->maxi={px,py,val};
        now->mini={px,py,val};
        return true;
    }
    now->reset();
    bool ok[4];
    ok[0]=update(son(0),xl.left(),yl.left(),px,py,val);
    ok[1]=update(son(1),xl.right(),yl.left(),px,py,val);
    ok[2]=update(son(2),xl.left(),yl.right(),px,py,val);
    ok[3]=update(son(3),xl.right(),yl.right(),px,py,val);
    for (int i = 0; i < 4; ++i) {//更新now
        if(!ok[i])continue;
        treenode* son = getnode(son(i));
        now->maxi= son->maxi.val  >  now->maxi.val  ?  son->maxi  :  now->maxi;
        now->mini= son->mini.val  <  now->mini.val  ?  son->mini  :  now->mini;
    }
    return true;
}
void query(int p,interval xl,interval yl,interval qx,interval qy,int& ansmax,int& ansmin)
{
    if(xl.len()<=0||yl.len()<=0)return ;
    if(!xl.with(qx) || !yl.with(qy))return ;
    treenode* now = getnode(p);
    if(ansmax>=now->maxi.val && ansmin<=now->mini.val)return ;//最值优化
    if(qx.include(xl) && qy.include(yl)){
        ansmax=max(now->maxi.val,ansmax);
        ansmin=min(now->mini.val,ansmin);
        return ;
    }
    if(xl.len()==1&&yl.len()==1){ return;}
    query(son(0),xl.left(),yl.left(),qx,qy,ansmax,ansmin);
    query(son(1),xl.right(),yl.left(),qx,qy,ansmax,ansmin);
    query(son(2),xl.left(),yl.right(),qx,qy,ansmax,ansmin);
    query(son(3),xl.right(),yl.right(),qx,qy,ansmax,ansmin);
}
int main()
{
    short n;
    scanf("%hd",&n);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            scanf("%d",&a[i][j]);
        }
    }
    build(1,{1,n},{1,n});
    int q;
    scanf("%d",&q);
    while(q--)
    {
        getchar();
        char ch;
        scanf("%c ",&ch);
        if(ch=='q')
        {
            interval x,y;
            scanf("%hd%hd%hd%hd",&x.l,&y.l,&x.r,&y.r);
            if(x.l>x.r)swap(x.l,x.r);
            if(y.l>y.r)swap(y.l,y.r);
            int ansmax=INT_MIN,ansmin=INT_MAX;
            query(1,{1,n},{1,n},x,y,ansmax,ansmin);
            printf("%d %d\n",ansmax,ansmin);
        }
        else
        {
            short x,y;
            int val;
            scanf("%hd%hd%d",&x,&y,&val);
            update(1,{1,n},{1,n},x,y,val);
        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值