C80 二维线段树+标记永久化 区修+区查 P3437 [POI2006] TET-Tetris 3D

视频链接:266 二维线段树+标记永久化 区修+区查 P3437 [POI2006] TET-Tetris 3D_哔哩哔哩_bilibili

 

 

 

 

Luogu P3437 [POI2006] TET-Tetris 3D

复制代码
// 二维线段树+标记永久化 区修+区查  空间:O(D*4*D*4) 时间:O(N*logD*logS)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define ls u<<1
#define rs u<<1|1
#define mid (l+r>>1)
const int M=4005;
int D,S,N;
struct segY{ //内树
  int mx[M],tag[M]; //区间最值,永久标记
  void change(int u,int l,int r,int y1,int y2,int h){ //内修
    mx[u]=max(mx[u],h); //经过则更新mx
    if(y1<=l&&r<=y2){tag[u]=max(tag[u],h);return;}//覆盖则更新tag
    if(y1<=mid) change(ls,l,mid,y1,y2,h);
    if(y2>mid) change(rs,mid+1,r,y1,y2,h);
  }
  int query(int u,int l,int r,int y1,int y2){ //内查
    if(y1<=l&&r<=y2) return mx[u]; //覆盖则返回mx
    int ans=tag[u]; //先取tag,再裂开找
    if(y1<=mid) ans=max(ans,query(ls,l,mid,y1,y2));
    if(y2>mid) ans=max(ans,query(rs,mid+1,r,y1,y2));
    return ans;
  }
}mx[M],tag[M]; //外树每个节点维护两颗内树mx,tag

void change(int u,int l,int r,int x1,int x2,int y1,int y2,int h){ //外修
  mx[u].change(1,1,S,y1,y2,h); //经过则入内树mx
  if(x1<=l&&r<=x2){tag[u].change(1,1,S,y1,y2,h);return;}//覆盖则入内树tag
  if(x1<=mid) change(ls,l,mid,x1,x2,y1,y2,h);
  if(x2>mid) change(rs,mid+1,r,x1,x2,y1,y2,h);
}
int query(int u,int l,int r,int x1,int x2,int y1,int y2){ //外查
  if(x1<=l&&r<=x2) return mx[u].query(1,1,S,y1,y2); //覆盖则入内树mx
  int ans=tag[u].query(1,1,S,y1,y2); //先入内树tag,再裂开找
  if(x1<=mid) ans=max(ans,query(ls,l,mid,x1,x2,y1,y2));
  if(x2>mid) ans=max(ans,query(rs,mid+1,r,x1,x2,y1,y2));
  return ans;
}
int main(){
  scanf("%d%d%d",&D,&S,&N); int d,s,h,x,y;
  while(N--){
    scanf("%d%d%d%d%d",&d,&s,&h,&x,&y),++x,++y; //偏移
    h+=query(1,1,D,x,x+d-1,y,y+s-1); //累计当前区间高度
    change(1,1,D,x,x+d-1,y,y+s-1,h); //更新当前区间高度
  }
  printf("%d\n",mx[1].mx[1]);
}
复制代码

 

复制代码
// 二维线段树+标记永久化+动态开点 区修+区查 时空复杂度:O(N*logD*logS)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define ls u<<1
#define rs u<<1|1
#define mid (l+r>>1)
const int M=2e6+5;
int D,S,N;
struct segY{ //内树
    int tot,lc[M],rc[M],mx[M],tag[M]; //mx区间最值,tag永久标记
  void change(int& u,int l,int r,int y1,int y2,int h){ //内修
    if(!u) u=++tot;     //内树开点
    mx[u]=max(mx[u],h); //经过则更新mx
    if(y1<=l&&r<=y2){tag[u]=max(tag[u],h);return;} //覆盖则更新tag
    if(y1<=mid) change(lc[u],l,mid,y1,y2,h);
    if(y2>mid) change(rc[u],mid+1,r,y1,y2,h);
  }
  int query(int u,int l,int r,int y1,int y2){ //内查
    if(y1<=l&&r<=y2) return mx[u]; //覆盖则返回mx
    int ans=tag[u]; //先取tag,再裂开找
    if(y1<=mid) ans=max(ans,query(lc[u],l,mid,y1,y2));
    if(y2>mid) ans=max(ans,query(rc[u],mid+1,r,y1,y2));
    return ans;
  }
}Y;

int mx[4005],tag[4005]; //外树的每个节点维护两颗内树mx,tag
void change(int u,int l,int r,int x1,int x2,int y1,int y2,int h){ //外修
  Y.change(mx[u],1,S,y1,y2,h); //经过则入内树mx
  if(x1<=l&&r<=x2){Y.change(tag[u],1,S,y1,y2,h);return;}//覆盖则入内树tag
  if(x1<=mid) change(ls,l,mid,x1,x2,y1,y2,h);
  if(x2>mid) change(rs,mid+1,r,x1,x2,y1,y2,h);
}
int query(int u,int l,int r,int x1,int x2,int y1,int y2){ //外查
  if(x1<=l&&r<=x2) return Y.query(mx[u],1,S,y1,y2); //覆盖则入内树mx
  int ans=Y.query(tag[u],1,S,y1,y2); //先入内树tag,再裂开找
  if(x1<=mid) ans=max(ans,query(ls,l,mid,x1,x2,y1,y2));
  if(x2>mid) ans=max(ans,query(rs,mid+1,r,x1,x2,y1,y2));
  return ans;
}
int main(){
  scanf("%d%d%d",&D,&S,&N); int d,s,h,x,y;
  while(N--){
    scanf("%d%d%d%d%d",&d,&s,&h,&x,&y),++x,++y; //偏移
    h+=query(1,1,D,x,x+d-1,y,y+s-1); //累计当前区间高度
    change(1,1,D,x,x+d-1,y,y+s-1,h); //更新当前区间高度
  }
  printf("%d\n",query(1,1,D,1,D,1,S));
}
复制代码

  

POJ2155 Matrix

区修:把矩形区域{(x1,y1),(x2,y2)}的0改为1,1改为0
点查:查询某一个点的值是0还是1

思路:只对覆盖区间做翻转修改,不用标记。
          查询时,累计经过区间的1的个数,即目标点被修改的次数 num。
          若 num 为奇数则输出 1,为偶数则输出 0。

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

#define N 1005
#define uls u<<1
#define urs u<<1|1
#define vls v<<1
#define vrs v<<1|1
#define mid ((l+r)>>1)
bool val[N<<2][N<<2];
int  X,n,T,num,x1,x2,y1,y2;

void changeY(int u,int v,int l,int r){ //内修
  if(y1<=l && r<=y2){ //内层覆盖即修改
    val[u][v]=!val[u][v]; return;
  }
  if(y1<=mid) changeY(u,vls,l,mid);
  if(y2>mid) changeY(u,vrs,mid+1,r);
}
void changeX(int u,int l,int r){ //外修
  if(x1<=l && r<=x2){ //外层覆盖即入内
    changeY(u,1,1,n); return;
  }
  if(x1<=mid) changeX(uls,l,mid);
  if(x2>mid) changeX(urs,mid+1,r);
}
void queryY(int u,int v,int l,int r){ //内查
  if(val[u][v]) num++; //内层经过节点有标记则累计
  if(l==r) return;
  if(y1<=mid) queryY(u,vls,l,mid);
  else queryY(u,vrs,mid+1,r);
}
void queryX(int u,int l,int r){ //外查
  queryY(u,1,1,n); //外层经过节点均入内
  if(l==r) return;
  if(x1<=mid) queryX(uls,l,mid);
  else queryX(urs,mid+1,r);
}
int main(){
  char op[2];
  while(~scanf("%d",&X)) while(X--){
    memset(val,0,sizeof(val));
    scanf("%d%d",&n,&T);
    for(int i=0;i<T;i++){
      scanf("%s%d%d",&op,&x1,&y1);
      if(*op=='C'){
        scanf("%d%d",&x2,&y2);
        changeX(1,1,n);
      }
      else{
        num=0;
        queryX(1,1,n); 
        if(num&1) printf("1\n");
        else printf("0\n");
      }
    }
    if(X) printf("\n");
  }
}
复制代码

 

posted @   董晓  阅读(148)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示