原题: http://acm.hdu.edu.cn/showproblem.php?pid=6638
题意:
给出 [ − 1 e 9 , 1 e 9 ] [-1e9,1e9] [−1e9,1e9]上的 2 e 3 2e3 2e3个点,求最大子矩阵。
解析:
一般的 O ( N 3 ) O(N^3) O(N3)的做法不能做了,考虑这个题的特点,虽然离散化后有 2 e 3 2e3 2e3种横坐标, 2 e 3 2e3 2e3种纵坐标,如果做 4 e 6 4e6 4e6个点的方法一定是不行了。
我们用 3 e 3 3e3 3e3个点的角度去考虑,先枚举上下边界,下边界往下延的过程中用线段树维护区间最大子段。
时间复杂度 O ( N 2 l o g N ) O(N^2log_N) O(N2logN)
代码:
#include
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define LL long long
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
const int maxn=2009;
int n;
struct Node {
LL Sum,Max,Lmax,Rmax;
} Tr[maxn<<2];
struct Uni {
int num;
LL tmp[maxn];
void init() {
sort(tmp+1,tmp+1+num);
num=unique(tmp+1,tmp+1+num)-tmp-1;
}
void transform(LL &val) {
val=lower_bound(tmp+1,tmp+1+num,val)-tmp;
}
} Ux,Uy;
void PushUp(Node &Ans,Node Lef,Node Rig) {
Ans.Sum=Lef.Sum+Rig.Sum;
Ans.Max=max(max(Lef.Max,Rig.Max),Lef.Rmax+Rig.Lmax);
Ans.Lmax=max(Lef.Lmax,Lef.Sum+Rig.Lmax);
Ans.Rmax=max(Rig.Rmax,Rig.Sum+Lef.Rmax);
}
void Build(int rt=1,int l=1,int r=Uy.num) {
Tr[rt].Sum=Tr[rt].Max=Tr[rt].Lmax=Tr[rt].Rmax=0;
if(l==r) {
return;
}
Build(ls,l,mid);
Build(rs,mid+1,r);
}
void Update(int pos,LL val,int rt=1,int l=1,int r=Uy.num) {
if(l==r) {
Tr[rt].Sum=Tr[rt].Max=Tr[rt].Lmax=Tr[rt].Rmax=Tr[rt].Sum+val;
return;
}
if(pos<=mid)
Update(pos,val,ls,l,mid);
else
Update(pos,val,rs,mid+1,r);
PushUp(Tr[rt],Tr[ls],Tr[rs]);
}
Node Query(int L=1,int R=Uy.num,int rt=1,int l=1,int r=Uy.num) {
if(l>=L&&r<=R) {
return Tr[rt];
}
if(R<=mid)
return Query(L,R,ls,l,mid);
if(L>mid)
return Query(L,R,rs,mid+1,r);
Node Ans,Lef=Query(L,R,ls,l,mid),Rig=Query(L,R,rs,mid+1,r);
PushUp(Ans,Lef,Rig);
return Ans;
}
struct Point {
LL x,y,val;
bool operator<(const Point &R)const{
return x<R.x;
}
} e[maxn];
int main() {
int _;
for(scanf("%d",&_); _--;) {
scanf("%d",&n);
rep(i,1,n) {
scanf("%lld%lld%lld",&e[i].x,&e[i].y,&e[i].val);
Ux.tmp[i]=e[i].x;
Uy.tmp[i]=e[i].y;
}
Ux.num=Uy.num=n;
Ux.init();
Uy.init();
rep(i,1,n) {
Ux.transform(e[i].x);
Uy.transform(e[i].y);
}
sort(e+1,e+1+n);
LL ans=0;
rep(i,1,Ux.num){
Build();
int At=1;
while(e[At].x<i)At++;
rep(j,i,Ux.num){
while(At<=n&&e[At].x==j)
Update(e[At].y,e[At].val),++At;
ans=max(ans,Query().Max);
}
}
printf("%lld\n",ans);
}
}