C77 二维线段树 (线段树套线段树) 点修+区查
视频链接:263 二维线段树 (线段树套线段树) 点修+区查_哔哩哔哩_bilibili
一个矩阵,初始化为全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; }
向一个 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"); } } } }
给定一个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); } } }