现在上真正的二维线段树 毕竟 刚刚那个是卡常 过题我们现在做一个更高级的做法二维线段树。
大体上维护一颗x轴线段树 然后在每个节点的下方再吊一颗维护y轴的线段树那么此时我们整个平面就被我们玩好了。
这样形成二维线段树比刚才的要 合理多了。
写起来 不免有点蒙蔽...然后突然就顿悟了 其实每次我们对于区间的修改大概就是先把x属于x轴的那一段区间给拎出来然后在那个区间之中把那个区间的y轴线段树给修改掉。

还是刚刚那道题 这次是MLE 了 理论上二维线段树空间复杂度 (MAXN<<2)^2这个复杂度 可是正中下怀的MLE了 开小了一点就可以过了。

//#include<bits/stdc++.h>
#include<iostream>
#include<iomanip>
#include<ctime>
#include<cstring>
#include<string>
#include<ctime>
#include<cctype>
#include<cstdio>
#include<utility>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<set>
#include<bitset>
#include<vector>
#include<algorithm>
#include<cstdlib>
#define INF 1000000000
#define ll long long
#define mx(p) t[p].mx
#define tag(p) t[p].tag
#define RE register
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
RE int x=0,f=1;RE char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
const int MAXN=3000;
int n,m,Q;
int qx,xx,qy,yy,h;
inline int max(int x,int y){return x>y?x:y;}
struct wy
{
int mx[MAXN],tag[MAXN];
inline void change(int p,int l,int r,int x,int y,int k)
{
mx[p]=max(mx[p],k);
if(l==x&&r==y)
{
tag[p]=max(tag[p],k);
return;
}
int mid=(l+r)>>1;
if(y<=mid)change(p<<1,l,mid,x,y,k);
else
{
if(x>mid)change(p<<1|1,mid+1,r,x,y,k);
else change(p<<1,l,mid,x,mid,k),change(p<<1|1,mid+1,r,mid+1,y,k);
}
}
inline int ask(int p,int l,int r,int x,int y)
{
if(l==x&&r==y)return mx[p];
int mid=(l+r)>>1,ans=tag[p];
if(y<=mid)ans=max(ans,ask(p<<1,l,mid,x,y));
else
{
if(x>mid)ans=max(ans,ask(p<<1|1,mid+1,r,x,y));
else ans=max(ans,max(ask(p<<1,l,mid,x,mid),ask(p<<1|1,mid+1,r,mid+1,y)));
}
return ans;
}
};
struct tx
{
wy mx[MAXN],tag[MAXN];
inline void change(int p,int l,int r,int x,int y,int k)
{
mx[p].change(1,1,m,qy,yy,k);
if(l==x&&r==y)
{
tag[p].change(1,1,m,qy,yy,k);
return;
}
int mid=(l+r)>>1;
if(y<=mid)change(p<<1,l,mid,x,y,k);
else
{
if(x>mid)change(p<<1|1,mid+1,r,x,y,k);
else change(p<<1,l,mid,x,mid,k),change(p<<1|1,mid+1,r,mid+1,y,k);
}
}
inline int ask(int p,int l,int r,int x,int y)
{
if(l==x&&r==y)return mx[p].ask(1,1,m,qy,yy);
int mid=(l+r)>>1,ans=tag[p].ask(1,1,m,qy,yy);
if(y<=mid)ans=max(ans,ask(p<<1,l,mid,x,y));
else
{
if(x>mid)ans=max(ans,ask(p<<1|1,mid+1,r,x,y));
else
{
ans=max(ans,ask(p<<1,l,mid,x,mid));
ans=max(ans,ask(p<<1|1,mid+1,r,mid+1,y));
}
}
return ans;
}
}T;
int main()
{
freopen("1.in","r",stdin);
n=read();m=read();Q=read();
while(Q--)
{
xx=read();yy=read();h=read();
qx=read()+1;qy=read()+1;
xx=qx+xx-1;yy=qy+yy-1;
int ans=T.ask(1,1,n,qx,xx);
T.change(1,1,n,qx,xx,ans+h);
}
qx=1;qy=1;xx=n;yy=m;
printf("%d\n",T.ask(1,1,n,qx,xx));
return 0;
}
操作还是不太熟悉 觉得这个可持久化有点神仙没写过有点 怀疑 不过正确性 和 合理性都是比较显然的。
简述一下大体的思路吧 首先对x轴开一棵线段树然后 在x轴的这颗线段树每个节点处都吊着一棵y轴的线段树。
下传修改标记 的时候 对于到过路径上的所有的节点都应该修改值 因为这是标记所致 到了锁定的区间之后标记永久化 对这个tag打上标记 而对内部的y轴线段树也进行一次标记永久化。
通俗的来说 内外线段树处理方式一模一样。为什么不能下传标记 显然的是我们对于外层线段树的修改 在自己的内部是无法下传的 因为标记是无法合并的 比如说 ta 要修改1 n 1 2这个区间ta又要修改1 n 1 3这个区间显然这两个区间在x线段树上是对等的在y线段树上可并不对等所以这两个标记很难合并 故应该标记永久化减少合并的麻烦。
这里我们很完美的解决了 二维线段树的问题。 单次操作时间显然是 logn^2.
