二维线段树/树套树+标记永久化
作者:互联网
题目这里
二维线段树类似于一棵四叉树,四个子节点分别为left_up,left_down,right_up,right_down
其他与一维类似,要判断是否有这些儿子,常数大导致TLE
其实用数组可以不用build
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define R register
#define EN printf("\n")
#define LL long long
inline LL mmax(LL a,LL b){return a>b?a:b;}
inline LL read(){
LL x=0,y=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') y=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=getchar();}
return x*y;
}
int n,m,k;
struct tr{
tr *lup,*ldown,*rup,*rdown;
LL max,changee;
}dizhi[2000006],*root=&dizhi[0];
int tot;
void build(tr *tree,int l,int r,int u,int d){
if(l==r&&u==d){tree->changee=tree->max=0;return;}
tree->lup=&dizhi[++tot];
tree->ldown=&dizhi[++tot];
tree->rup=&dizhi[++tot];
tree->rdown=&dizhi[++tot];
int midlr=(l+r)>>1,midud=(u+d)>>1;
build(tree->lup,l,midlr,u,midud);
if(u!=d) build(tree->ldown,l,midlr,midud+1,d);
if(l!=r){
build(tree->rup,midlr+1,r,u,midud);
if(u!=d) build(tree->rdown,midlr+1,r,midud+1,d);
}
tree->max=tree->changee=0;
}
inline void pushdown(tr *tree){
if(!tree->changee) return;
tree->lup->max=tree->changee;tree->lup->changee=tree->changee;
tree->ldown->max=tree->changee;tree->ldown->changee=tree->changee;
tree->rup->max=tree->changee;tree->rup->changee=tree->changee;
tree->rdown->max=tree->changee;tree->rdown->changee=tree->changee;
tree->changee=0;
}
void change(tr *tree,int l,int r,int u,int d,int ql,int qr,int qu,int qd,LL h){
if(ql<=l&&r<=qr&&qu<=u&&d<=qd){
tree->max=h;
tree->changee=h;
return;
}
pushdown(tree);
int midlr=(l+r)>>1,midud=(u+d)>>1;
if(ql<=midlr){
if(qu<=midud) change(tree->lup,l,midlr,u,midud,ql,qr,qu,qd,h);
if(qd>midud&&u!=d) change(tree->ldown,l,midlr,midud+1,d,ql,qr,qu,qd,h);
}
if(qr>midlr&&l!=r){
if(qu<=midud) change(tree->rup,midlr+1,r,u,midud,ql,qr,qu,qd,h);
if(qd>midud&&u!=d) change(tree->rdown,midlr+1,r,midud+1,d,ql,qr,qu,qd,h);
}
tree->max=mmax(mmax(tree->lup->max,tree->ldown->max),mmax(tree->rup->max,tree->rdown->max));
}
LL q(tr *tree,int l,int r,int u,int d,int ql,int qr,int qu,int qd){
if(ql<=l&&r<=qr&&qu<=u&&d<=qd) return tree->max;
pushdown(tree);
LL ret=-999999999999;
int midlr=(l+r)>>1,midud=(u+d)>>1;
if(ql<=midlr){
if(qu<=midud) ret=std::max(ret,q(tree->lup,l,midlr,u,midud,ql,qr,qu,qd));
if(qd>midud&&u!=d) ret=std::max(ret,q(tree->ldown,l,midlr,midud+1,d,ql,qr,qu,qd));
}
if(qr>midlr&&l!=r){
if(qu<=midud) ret=std::max(ret,q(tree->rup,midlr+1,r,u,midud,ql,qr,qu,qd));
if(qd>midud&&u!=d) ret=std::max(ret,q(tree->rdown,midlr+1,r,midud+1,d,ql,qr,qu,qd));
}
return ret;
}
int main(){
n=read();m=read();k=read();
build(root,1,n,1,m);
int x,y,nn,mm;LL h;
for(R int i=1;i<=k;i++){
nn=read();mm=read();h=read();x=read();y=read();
x++;y++;
h+=q(root,1,n,1,m,x,x+nn-1,y,y+mm-1);
change(root,1,n,1,m,x,x+nn-1,y,y+mm-1,h);
}
printf("%lld",root->max);
return 0;
}
另一种方法是外层线段树维护x轴,每个节点对应两棵内层维护y轴的树(max树,tag树)
标记永久化:
max数组是区间最大值,tag为修改后的值
查询时:若完全包含某个区间,才用max更新(因为max是整个区间的最大值),否则,用tag(tag是对整个区间打的,所以子区间可以直接使用)
修改:完全包含,用k更新tag,否则用max
数组省去build后最大测试点679ms
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define R register
#define EN printf("\n")
#define LL long long
inline int read(){
int x=0,y=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') y=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=getchar();}
return x*y;
}
inline int mmax(int a,int b){return a>b?a:b;}
int n,m,k;
struct segy{
int max[4020],tag[4020];
int q(int o,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr) return mmax(max[o],tag[o]);
int mid=(l+r)>>1;
int ret=-99999999;
if(ql<=mid) ret=q(o<<1,l,mid,ql,qr);
if(qr>mid) ret=mmax(ret,q(o<<1|1,mid+1,r,ql,qr));
return mmax(ret,tag[o]);
}
void change(int o,int l,int r,int ql,int qr,int k){
max[o]=mmax(max[o],k);
if(ql<=l&&r<=qr){tag[o]=mmax(tag[o],k);return;}
int mid=(l+r)>>1;
if(ql<=mid) change(o<<1,l,mid,ql,qr,k);
if(qr>mid) change(o<<1|1,mid+1,r,ql,qr,k);
}
};
struct segx{
segy tag[4020],max[4020];
int q(int o,int l,int r,int ql,int qr,int u,int d){
if(ql<=l&&r<=qr) return max[o].q(1,1,m,u,d);
int mid=(l+r)>>1;
int ret=-99999999;
if(ql<=mid) ret=mmax(ret,q(o<<1,l,mid,ql,qr,u,d));
if(qr>mid) ret=mmax(ret,q(o<<1|1,mid+1,r,ql,qr,u,d));
return mmax(ret,tag[o].q(1,1,m,u,d));
}
void change(int o,int l,int r,int ql,int qr,int u,int d,int k){
max[o].change(1,1,m,u,d,k);
if(ql<=l&&r<=qr){tag[o].change(1,1,m,u,d,k);return;}
int mid=(l+r)>>1;
if(ql<=mid) change(o<<1,l,mid,ql,qr,u,d,k);
if(qr>mid) change(o<<1|1,mid+1,r,ql,qr,u,d,k);
}
}a;
int main(){
n=read();m=read();k=read();
int nn,mm,x,y,h;
for(R int i=1;i<=k;i++){
nn=read();mm=read();h=read();x=read()+1;y=read()+1;
h+=a.q(1,1,n,x,x+nn-1,y,y+mm-1);
a.change(1,1,n,x,x+nn-1,y,y+mm-1,h);
}
printf("%d",a.q(1,1,n,1,n,1,m));
return 0;
}
标签:midlr,树套,int,max,线段,tree,永久化,midud,changee 来源: https://www.cnblogs.com/suxxsfe/p/12425368.html