C77 二维线段树 (线段树套线段树) 点修+区查

视频链接:263 二维线段树 (线段树套线段树) 点修+区查_哔哩哔哩_bilibili

 

 

 

POJ1195 Mobile phones

一个矩阵,初始化为全0。有以下操作:
(1)将 (x,y) 元素加 a
(2)求矩阵 [(x1,y1),(x2,y2)] 所有元素的和

// 二维线段树 点修+区查 O(Q*logN*logN)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define N 1050
#define uls u<<1
#define urs u<<1|1
#define vls v<<1
#define vrs v<<1|1
#define mid ((l+r)>>1)
int n,sum[N<<2][N<<2]; //节点区间和

void changeY(int u,int v,int l,int r,int y,int a){ //内修
  sum[u][v]+=a; //内层经过的节点均修改
  if(l==r) return;
  if(y<=mid) changeY(u,vls,l,mid,y,a);
  else changeY(u,vrs,mid+1,r,y,a);
}
void changeX(int u,int l,int r,int x,int y,int a){ //外修
  changeY(u,1,1,n,y,a); //外层经过的节点均入内
  if(l==r) return;
  if(x<=mid) changeX(uls,l,mid,x,y,a);
  else changeX(urs,mid+1,r,x,y,a);
}
int queryY(int u,int v,int l,int r,int y1,int y2){ //内查
  if(y1<=l&&r<=y2) return sum[u][v]; //内层覆盖即返回
  if(y2<=mid) return queryY(u,vls,l,mid,y1,y2);
  else if(y1>mid) return queryY(u,vrs,mid+1,r,y1,y2);
  else return queryY(u,vls,l,mid,y1,mid)
              +queryY(u,vrs,mid+1,r,mid+1,y2);
}
int queryX(int u,int l,int r,int x1,int x2,int y1,int y2){ //外查
  if(x1<=l&&r<=x2) return queryY(u,1,1,n,y1,y2); //外层覆盖即入内
  if(x2<=mid) return queryX(uls,l,mid,x1,x2,y1,y2);
  else if(x1>mid) return queryX(urs,mid+1,r,x1,x2,y1,y2);
  else return queryX(uls,l,mid,x1,mid,y1,y2)
              +queryX(urs,mid+1,r,mid+1,x2,y1,y2);
}
int main(){
  int op,x,y,a,x1,x2,y1,y2;
  while(~scanf("%d",&op)){
    if(op==0) scanf("%d",&n),
              memset(sum,0,sizeof(sum));
    if(op==1) scanf("%d%d%d",&x,&y,&a),
              changeX(1,1,n,x+1,y+1,a);
    if(op==2) scanf("%d%d%d%d",&x1,&y1,&x2,&y2),
              printf("%d\n",queryX(1,1,n,x1+1,x2+1,y1+1,y2+1));
    if(op==3) break;
  }
  return 0;
}

 

// 二维线段树 点修+区查 O(Q*logN*logN)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define N 1050
#define uls u<<1
#define urs u<<1|1
#define vls v<<1
#define vrs v<<1|1
#define mid ((l+r)>>1)
int n,S,sum[N<<2][N<<2]; //节点区间和

void changeY(int u,int v,int l,int r,int y,int a){ //内修
  sum[u][v]+=a; //内层经过的节点均修改
  if(l==r) return;
  if(y<=mid) changeY(u,vls,l,mid,y,a);
  else changeY(u,vrs,mid+1,r,y,a);
}
void changeX(int u,int l,int r,int x,int y,int a){ //外修
  changeY(u,1,1,n,y,a); //外层经过的节点均入内
  if(l==r) return;
  if(x<=mid) changeX(uls,l,mid,x,y,a);
  else changeX(urs,mid+1,r,x,y,a);
}
void queryY(int u,int v,int l,int r,int y1,int y2){ //内查
  if(y1<=l&&r<=y2){
    S+=sum[u][v]; //内层覆盖即更新
    return;
  }
  if(y1<=mid) queryY(u,vls,l,mid,y1,y2);
  if(y2>mid) queryY(u,vrs,mid+1,r,y1,y2);
}
void queryX(int u,int l,int r,int x1,int x2,int y1,int y2){ //外查
  if(x1<=l&&r<=x2){
    queryY(u,1,1,n,y1,y2); //外层覆盖即入内
    return;
  }
  if(x1<=mid) queryX(uls,l,mid,x1,x2,y1,y2);
  if(x2>mid) queryX(urs,mid+1,r,x1,x2,y1,y2);
}
int main(){
  int op,x,y,a,x1,x2,y1,y2;
  while(~scanf("%d",&op)){
    if(op==0) scanf("%d",&n),
              memset(sum,0,sizeof(sum));
    if(op==1) scanf("%d%d%d",&x,&y,&a),
              changeX(1,1,n,x+1,y+1,a);
    if(op==2) scanf("%d%d%d%d",&x1,&y1,&x2,&y2),S=0,
              queryX(1,1,n,x1+1,x2+1,y1+1,y2+1),
              printf("%d\n",S);
    if(op==3) break;
  }
  return 0;
}

 

HDU1823 Luck and Love

向一个 100*1000 的二维空间中插入点,查询区间最大值

// 二维线段树 点修+区查 O(T*logN*logM)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define uls u<<1
#define urs u<<1|1
#define vls v<<1
#define vrs v<<1|1
#define mid ((l+r)>>1)
const int N=105,M=1005;
int T,MX;
int mx[N<<2][M<<2]; //节点区间最大值

void changeY(int u,int v,int l,int r,int y,int a){ //内修
  mx[u][v]=max(mx[u][v],a); //内层经过的节点均修改
  if(l==r) return;
  if(y<=mid) changeY(u,vls,l,mid,y,a);
  else changeY(u,vrs,mid+1,r,y,a);
}
void changeX(int u,int l,int r,int x,int y,int a){ //外修
  changeY(u,1,1,M,y,a); //外层经过的节点均入内
  if(l==r) return;
  if(x<=mid) changeX(uls,l,mid,x,y,a);
  else changeX(urs,mid+1,r,x,y,a);
}
void queryY(int u,int v,int l,int r,int y1,int y2){ //内查
  if(y1<=l&&r<=y2){
    MX=max(MX,mx[u][v]); //内层覆盖即更新
    return;
  }
  if(y1<=mid) queryY(u,vls,l,mid,y1,y2);
  if(y2>mid) queryY(u,vrs,mid+1,r,y1,y2);
}
void queryX(int u,int l,int r,int x1,int x2,int y1,int y2){ //外查
  if(x1<=l&&r<=x2){
    queryY(u,1,1,M,y1,y2); //外层覆盖即入内
    return;
  }
  if(x1<=mid) queryX(uls,l,mid,x1,x2,y1,y2);
  if(x2>mid) queryX(urs,mid+1,r,x1,x2,y1,y2);
}
int main(){
  while(~scanf("%d",&T)){
    if(T==0) break;
    memset(mx,0,sizeof(mx));
    while(T--){
      char op[2]; scanf("%s",op);
      if(*op=='I'){
        int h,b; double a,l;
        scanf("%d%lf%lf",&h,&a,&l);
        h-=99; b=a*10+1;
        changeX(1,1,N,h,b,l*10);
      }
      else if(*op=='Q'){
        int h1,h2,b1,b2; double a1,a2;
        scanf("%d%d%lf%lf",&h1,&h2,&a1,&a2);
        h1-=99;h2-=99;b1=a1*10+1;b2=a2*10+1;
        if(h1>h2) swap(h1,h2);
        if(b1>b2) swap(b1,b2);
        MX=0; queryX(1,1,N,h1,h2,b1,b2);
        if(MX) printf("%.1lf\n",MX/10.0);
        else puts("-1");
      }
    }
  }
}

 

HDU4819 Mosaic

给定一个N*N的矩阵,每个格子都有一个数,再给出Q个询问,每次询问以(x,y)为中心的边长为L(L必为奇数)
的正方形矩阵中的最大值和最小值,并修改(x,y)的值为 (MAX+MIN)/2

// 二维线段树 点修+区查 O(Q*logN*logN)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int INF=1e9, N=805;
#define uls u<<1
#define urs u<<1|1
#define vls v<<1
#define vrs v<<1|1
#define mid ((l+r)>>1)
int T,n,Q,MI,MX,a[N][N];
int mi[N<<2][N<<2],mx[N<<2][N<<2];

void pushupX(int u,int v){ //X上传
  mx[u][v]=max(mx[uls][v],mx[urs][v]);
  mi[u][v]=min(mi[uls][v],mi[urs][v]);
}
void pushupY(int u,int v){ //Y上传
  mx[u][v]=max(mx[u][vls],mx[u][vrs]);
  mi[u][v]=min(mi[u][vls],mi[u][vrs]);
}
void buildY(int u,int v,int l,int r,int x){ //内建
  if(l==r){
    if(x) mx[u][v]=mi[u][v]=a[x][l]; //非0时取a
    else pushupX(u,v); //0时用该列的行信息更新
    return;
  }
  buildY(u,vls,l,mid,x);
  buildY(u,vrs,mid+1,r,x);
  pushupY(u,v);
}
void buildX(int u,int l,int r){ //外建
  if(l==r){
    buildY(u,1,1,n,l); //叶子时传入行坐标
    return;
  }
  buildX(uls,l,mid);
  buildX(urs,mid+1,r);
  buildY(u,1,1,n,0); //非叶子时传入0
}
void changeY(int u,int v,int l,int r,int y,int val){ //内修
  if(l==r){
    if(val) mx[u][v]=mi[u][v]=val; //非0时取新值
    else pushupX(u,v); //0时用该列的行信息更新
    return;
  }
  if(y<=mid) changeY(u,vls,l,mid,y,val);
  else changeY(u,vrs,mid+1,r,y,val);
  pushupY(u,v);
}
void changeX(int u,int l,int r,int x,int y,int val){ //外修
  if(l==r){
    changeY(u,1,1,n,y,val); //叶子时传入新值
    return;
  }
  if(x<=mid) changeX(uls,l,mid,x,y,val);
  else changeX(urs,mid+1,r,x,y,val);
  changeY(u,1,1,n,y,0); //非叶子时传入0
}
void queryY(int u,int v,int l,int r,int y1,int y2){ //内查
  if(y1<=l&&r<=y2){
    MX=max(MX,mx[u][v]);
    MI=min(MI,mi[u][v]);
    return;
  }
  if(y1<=mid) queryY(u,vls,l,mid,y1,y2);
  if(y2>mid) queryY(u,vrs,mid+1,r,y1,y2);
}
void queryX(int u,int l,int r,int x1,int x2,int y1,int y2){ //外查
  if(x1<=l&&r<=x2){
    queryY(u,1,1,n,y1,y2); 
    return;
  }
  if(x1<=mid) queryX(uls,l,mid,x1,x2,y1,y2);
  if(x2>mid) queryX(urs,mid+1,r,x1,x2,y1,y2);
}
int main(){
  scanf("%d",&T);
  for(int k=1,x,y,z; k<=T; k++){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
    buildX(1,1,n);
    printf("Case #%d:\n",k);
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++){
      scanf("%d%d%d",&x,&y,&z);
      z/=2; MX=-INF,MI=INF;
      queryX(1,1,n,max(1,x-z),min(x+z,n),max(1,y-z),min(y+z,n));
      changeX(1,1,n,x,y,(MX+MI)/2);
      printf("%d\n",(MX+MI)/2);
    }
  }
}

 

// 二维线段树 点修+区查 O((N^2+Q)*logN*logN)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int INF=1e9, N=805;
#define uls u<<1
#define urs u<<1|1
#define vls v<<1
#define vrs v<<1|1
#define mid ((l+r)>>1)
int T,n,Q,MI,MX,a[N][N];
int mi[N<<2][N<<2],mx[N<<2][N<<2];

void pushupX(int u,int v){ //X上传
  mx[u][v]=max(mx[uls][v],mx[urs][v]);
  mi[u][v]=min(mi[uls][v],mi[urs][v]);
}
void pushupY(int u,int v){ //Y上传
  mx[u][v]=max(mx[u][vls],mx[u][vrs]);
  mi[u][v]=min(mi[u][vls],mi[u][vrs]);
}
void changeY(int u,int v,int l,int r,int y,int val){ //内修
  if(l==r){
    if(val) mx[u][v]=mi[u][v]=val; //非0时取新值
    else pushupX(u,v); //0时用该列的行信息更新
    return;
  }
  if(y<=mid) changeY(u,vls,l,mid,y,val);
  else changeY(u,vrs,mid+1,r,y,val);
  pushupY(u,v);
}
void changeX(int u,int l,int r,int x,int y,int val){ //外修
  if(l==r){
    changeY(u,1,1,n,y,val); //叶子时传入新值
    return;
  }
  if(x<=mid) changeX(uls,l,mid,x,y,val);
  else changeX(urs,mid+1,r,x,y,val);
  changeY(u,1,1,n,y,0); //非叶子时传入0
}
void queryY(int u,int v,int l,int r,int y1,int y2){ //内查
  if(y1<=l&&r<=y2){
    MX=max(MX,mx[u][v]);
    MI=min(MI,mi[u][v]);
    return;
  }
  if(y1<=mid) queryY(u,vls,l,mid,y1,y2);
  if(y2>mid) queryY(u,vrs,mid+1,r,y1,y2);
}
void queryX(int u,int l,int r,int x1,int x2,int y1,int y2){ //外查
  if(x1<=l&&r<=x2){
    queryY(u,1,1,n,y1,y2); 
    return;
  }
  if(x1<=mid) queryX(uls,l,mid,x1,x2,y1,y2);
  if(x2>mid) queryX(urs,mid+1,r,x1,x2,y1,y2);
}
int main(){
  scanf("%d",&T);
  for(int k=1,x,y,z; k<=T; k++){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++) scanf("%d",&x),changeX(1,1,n,i,j,x);
    printf("Case #%d:\n",k);
    scanf("%d",&Q);
    for(int i=1;i<=Q;i++){
      scanf("%d%d%d",&x,&y,&z);
      z/=2; MX=-INF,MI=INF;
      queryX(1,1,n,max(1,x-z),min(x+z,n),max(1,y-z),min(y+z,n));
      changeX(1,1,n,x,y,(MX+MI)/2);
      printf("%d\n",(MX+MI)/2);
    }
  }
}

 

posted @ 2023-12-15 17:09  董晓  阅读(193)  评论(0编辑  收藏  举报