题目链接:HDU - 6638
题意:二维平面内n个点,有不同的点权,问随便一个矩形(平行于x,y轴)能圈住的最大权值和为多少,可以不选。
二维的最大子段和。
谁如果把这道题中的东西离散化成一个矩阵,谁傻逼(我傻逼),离散化成这个东西的话复杂度就是
n
3
n^3
n3起步了。
具体来,离散化了x,y,然后记录每个x对应的y出现的位置及他的权值。
枚举上下边界,每次刚开始枚举的时候建一颗全部为0的线段树(离散化后的y的范围),然后下边界每下移一次,把与他同等高度的权值加到对应的点中去。
赛中一度将这个东西映射成了一个矩阵,复杂度一直压不下来。。。。。(因为本来这些点构成了一个稀疏矩阵,压缩就会变成一个稠密矩阵,里面有很多0的元素,而加0是没有意义的,所以压缩了矩阵会使复杂度多一个n)
当然这个题的时间复杂度要分析对,直观来看代码中的复杂度似乎为
n
3
∗
l
o
g
2
n
n^3*log_2n
n3∗log2n,但是第二三重的循环加起来总共最多会执行n次,而一次的复杂度为log,故其实复杂度为:
n
2
∗
l
o
g
2
n
n^2*log_2n
n2∗log2n
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2009;
ll sum[maxn<<2|1];
ll dat[maxn<<2|1];
ll lmax[maxn<<2|1];
ll rmax[maxn<<2|1];
void pushup(int k){
sum[k]=sum[k<<1]+sum[k<<1|1];
lmax[k]=max(lmax[k<<1],sum[k<<1]+lmax[k<<1|1]);
rmax[k]=max(rmax[k<<1|1],sum[k<<1|1]+rmax[k<<1]);
dat[k]=max(max(dat[k<<1],dat[k<<1|1]),rmax[k<<1]+lmax[k<<1|1]);
}
void build(int l,int r,int k){
sum[k]=dat[k]=lmax[k]=rmax[k]=0;
if(l==r) return ;
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
}
void updata(int l,int r,int k,int id,ll val){
if(l==r){
dat[k]=rmax[k]=lmax[k]=sum[k]=sum[k]+val;
return ;
}
int mid=(l+r)>>1;
if(id<=mid) updata(l,mid,k<<1,id,val);
else updata(mid+1,r,k<<1|1,id,val);
pushup(k);
}
int X[maxn],Y[maxn];
int m1,m2;
ll mutil[maxn][maxn];
void quchong(int n){
sort(X+1,X+1+n);
sort(Y+1,Y+1+n);
m1=unique(X+1,X+1+n)-X-1;
m2=unique(Y+1,Y+1+n)-Y-1;
}
int getidx(int x){
return lower_bound(X+1,X+1+m1,x)-X;
}
int getidy(int x){
return lower_bound(Y+1,Y+1+m2,x)-Y;
}
struct Node{
int x,y,z;
}a[maxn];
vector<pair<int,int> > v[maxn];
int main(){
int t;
scanf("%d",&t);
int n;
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
X[i]=a[i].x;
Y[i]=a[i].y;
}
quchong(n);
for(int i=1;i<=n;++i){
int hx=getidx(a[i].x);
int hy=getidy(a[i].y);
v[hx].push_back({hy,a[i].z});
}
ll res=0;
for(int i=1;i<=m1;++i){
build(1,m2,1);
for(int j=i;j<=m1;++j){
for(int k=0;k<v[j].size();++k)
updata(1,m2,1,v[j][k].first,v[j][k].second);
res=max(res,dat[1]);
}
}
printf("%lld\n",res);
for(int i=1;i<=m1;++i) v[i].clear();
}
return 0;
}