传送门
这道题最主要的idea在于一个转化思想,原题是有若干带权点,求一个可能的矩形,可以转化成有若干个带权矩形,权可以累加,求一个最大的交。
做法就是,对于每一个点,预处理一个范围,这个范围表示当窗的右上角在这个范围内时可以覆盖当前点。很显然这个范围是一个矩形,记这个矩形的权为点权。那么我们就得到了n个带权矩形。求最大的交可以用扫描线来实现,将纵坐标离散化横坐标排序,然后从左往右扫,遇到矩形的左边界就在当前矩形的纵坐标范围内加上矩形的权,遇到右边界就减去,每次操作的全局最大值即为可能的最大交。维护用线段树实现。
当n<=100的时候 O(n3) 暴力就有60分辣= =不过在考场上忘清ans了然后就全挂了= =讨来一顿打
#include
#include
#include
#include
using namespace std;
#define N 10005
#define LL long long
int n,yy,cnt,lsh,now,ans;LL w,h;
struct hp{int x,z;LL y;}star[N];
struct hq{int l,r,val;LL x;}squ[N*2];
int p[N*2],loc[N*2],maxn[N*8],delta[N*8];
LL Y[N*2];
inline void clear()
{
ans=0; yy=0; cnt=0; lsh=0; memset(maxn,0,sizeof(maxn)); memset(delta,0,sizeof(delta));
memset(p,0,sizeof(p)); memset(Y,0,sizeof(Y)); memset(loc,0,sizeof(loc));
}
inline int cmp(int x,int y)
{
return Y[x]int cmps(hq a,hq b)
{
return a.xb.val);
}
inline void update(int now)
{
maxn[now]=max(maxn[now<<1],maxn[now<<1|1]);
}
inline void pushdown(int now,int l,int r,int mid)
{
if (delta[now])
{
maxn[now<<1]+=delta[now]; delta[now<<1]+=delta[now];
maxn[now<<1|1]+=delta[now]; delta[now<<1|1]+=delta[now];
delta[now]=0;
}
}
inline void interval_change(int now,int l,int r,int lrange,int rrange,int v)
{
int mid=(l+r)>>1;
if (lrange<=l&&r<=rrange)
{
maxn[now]+=v;
delta[now]+=v;
return;
}
pushdown(now,l,r,mid);
if (lrange<=mid) interval_change(now<<1,l,mid,lrange,rrange,v);
if (mid+1<=rrange) interval_change(now<<1|1,mid+1,r,lrange,rrange,v);
update(now);
}
inline int query(int now,int l,int r,int lrange,int rrange)
{
int mid=(l+r)>>1,ans=0;
if (lrange<=l&&r<=rrange) return maxn[now];
pushdown(now,l,r,mid);
if (lrange<=mid) ans=max(ans,query(now<<1,l,mid,lrange,rrange));
if (mid+1<=rrange) ans=max(ans,query(now<<1|1,mid+1,r,lrange,rrange));
return ans;
}
int main()
{
while (~scanf("%d%lld%lld",&n,&w,&h))
{
clear();
for (int i=1;i<=n;++i) scanf("%lld%lld%d",&star[i].x,&star[i].y,&star[i].z);
for (int i=1;i<=n;++i)
{
squ[++cnt].x=star[i].x; squ[cnt].val=star[i].z;
squ[++cnt].x=star[i].x+w-1; squ[cnt].val=-star[i].z;
Y[++yy]=star[i].y,Y[++yy]=star[i].y+h-1;
}
for (int i=1;i<=yy;++i) p[i]=i;
sort(p+1,p+yy+1,cmp);
for (int i=1;i<=yy;++i)
if (Y[p[i]]!=Y[p[i-1]]) loc[p[i]]=++lsh;
else loc[p[i]]=lsh;
cnt=0; yy=0;
for (int i=1;i<=n;++i)
{
yy+=2;
squ[++cnt].l=loc[yy-1]; squ[cnt].r=loc[yy];
squ[++cnt].l=loc[yy-1]; squ[cnt].r=loc[yy];
}
sort(squ+1,squ+cnt+1,cmps);
for (int i=1;i<=cnt;++i)
{
interval_change(1,1,lsh,squ[i].l,squ[i].r,squ[i].val);
now=query(1,1,lsh,1,lsh);
if (now>ans) ans=now;
}
printf("%d\n",ans);
}
}
写错的地方:
1、2^31-1是int的范围,需要用到long long,数据范围别再搞错了。
2、每一个矩形会贡献两个边,数组不要开小了。