HDU 6638 Snowy Smile
题意:平面有\(n\)个有权值的点,求最大子矩阵和
离散化后按横坐标升序排序,\(n^2\)枚举矩阵左右边界,设\(v[i]\)表示在左右边界内所有纵坐标为\(i\)的点的权值和,求最大子段和即可,用线段树维护带修改的区间最大子段和
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2010;
#define ls (node<<1)
#define rs (node<<1|1)
int n;
struct s
{
int x,y,z;
}p[maxn];
int hx[maxn],hy[maxn];
struct Segtree
{
ll max,vl,vr,sum;
}Tree[maxn<<2];
void updata(int node)
{
Tree[node].max=max(Tree[ls].max,max(Tree[rs].max,Tree[ls].vr+Tree[rs].vl));
Tree[node].sum=Tree[ls].sum+Tree[rs].sum;
Tree[node].vl=max(Tree[ls].vl,Tree[ls].sum+Tree[rs].vl);
Tree[node].vr=max(Tree[rs].vr,Tree[rs].sum+Tree[ls].vr);
}
void add(int l,int r,int node,int ps,int to)
{
if(l==r)
{
Tree[node].sum+=to;
Tree[node].max+=to;
Tree[node].vl+=to;
Tree[node].vr+=to;
return ;
}
int mid=(l+r)>>1;
if(ps<=mid)
add(l,mid,ls,ps,to);
else
add(mid+1,r,rs,ps,to);
updata(node);
}
void clr(int l,int r,int node)
{
Tree[node].max=Tree[node].vl=Tree[node].vr=Tree[node].sum=0;
if(l==r)return ;
int mid=(l+r)>>1;
clr(l,mid,ls);
clr(mid+1,r,rs);
}
bool cmp(s a, s b)
{
return a.x<b.x;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
int tot=0;
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z);
hx[i]=p[i].x;
hy[i]=p[i].y;
}
sort(hx,hx+n);
sort(hy,hy+n);
int nx=unique(hx,hx+n)-hx;
int ny=unique(hy,hy+n)-hy;
for(int i=0;i<n;i++)
{
p[i].x=lower_bound(hx,hx+nx,p[i].x)-hx+1;
p[i].y=lower_bound(hy,hy+ny,p[i].y)-hy+1;
}
sort(p,p+n,cmp);
int pos=0,now=0;
ll ans=0;
for(int i=1;i<=nx;i++)
{
clr(1,ny,1);
for(int j=i,pos=now;j<=nx;j++)
{
while(pos<n&&p[pos].x==j)
{
add(1,ny,1,p[pos].y,p[pos].z);
pos++;
}
if(j==i)now=pos;
ans=max(ans,Tree[1].max);
}
}
printf("%lld\n",ans);
}
return 0;
}

浙公网安备 33010602011771号