POJ 2482 Stars in Your Window(离散化+线段树:扫描线)
http://poj.org/problem?id=2482
题意:有很多点在二维平面内,每个点有一个价值,给你一个平行坐标轴的矩形,只可以移动矩形,问矩形最多能包括多少价值和的点.
分析:
本题首先要转换一下,我们用矩形的中心点来描述这个矩形,然后对于每个星星,我们建立一个矩形中心的活动范围,即矩形中心在该范围内活动就可以覆盖到该星星.其实这个新矩形与原来的矩形长和宽都是相同的.所以我们要求的问题就变成了:任意一个区域(肯定也是矩形的)最多能被矩形覆盖的最大值.(即假如有价值为5和价值为3的矩形覆盖了一个区域,但是不仅仅是边界相交,,那么这片区域的价值为8).
另外题目中要求矩形的边界如果包括了星星就不算.现在转化为新矩形来看这个问题(本题目中我们用x轴作为扫描线的高度,y轴离散化为区域):
如果两个新矩形在平行于x轴的边上重合了,那么可以肯定这边不能算是包括了这两个星星.我们用线段树离散化y轴坐标的时候自然就可以避过这个问题,因为线段树上的每个叶节点表示的是一个半闭半开的区间[y1,y2),[y2,y3) 等.所以如果出现上面那张情况,线段树中的节点不可能会有被两个扫描线覆盖的.
如果两个矩形在平行于y轴的边上重合了一条边,由于此时x轴做扫描线高度,也就是说有两条扫描线重合了,其中一条是+v的下位边,另一条是-v的上位边.这时我们应该先-v在+v. 即我们要先处理上位边,再处理下位边.(否则将出错,仔细想想为什么).这个只需要我们在对所有扫描线排序的时候做点小处理即可.
关于线段树节点维护的信息(采用线保留型线段树):
cnt:保存的是当前节点被覆盖的值.cnt信息不上传也不下传,属于线保留型.
sum:表示该节点控制的区域内,被覆盖的最大值.
由于初始cnt和sum都为0,所以可以用memset代替build
PushUp操作和update操作是必须的.
过程中出了点错误, 由于空间只申请MAXN=10005,导致出错,因为点做多1W个,所以不同的Y坐标有2W个,所以线段树的节点应该是8W.下面的代码同样适合处理浮点数大小的矩阵和点.稍微修改下即可.
AC代码:141ms
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define lson i*2,l,m #define rson i*2+1,m+1,r const int MAXN=20000+5;//必须为2W,因为点有1W个,所以扫描线2W个,不同的Y坐标最多有2W个 int cnt[MAXN*4],sum[MAXN*4]; double Y[MAXN]; struct seg { double l,r,h; int d; seg(){} seg(double a,double b,double c,int d):l(a),r(b),h(c),d(d){} bool operator <(const seg&b)const { if(h == b.h) return d<b.d; return h<b.h; } }ss[MAXN]; void PushUp(int i) { sum[i]=max(sum[i*2],sum[i*2+1]) + cnt[i]; } void update(int ql,int qr,int v,int i,int l,int r) { if(ql<=l && r<=qr) { cnt[i]+=v; sum[i]+=v; return ; } int m=(l+r)>>1; if(ql<=m) update(ql,qr,v,lson); if(m<qr) update(ql,qr,v,rson); PushUp(i); } int main() { int n; double w,h; while(scanf("%d%lf%lf",&n,&w,&h)==3) { if(n==0) { printf("0\n"); continue; } double x,y; int val; int cnt_y=0,cnt_ss=0;//记录有多少个Y值和扫描线 for(int i=1;i<=n;i++) { scanf("%lf%lf%d",&x,&y,&val); ss[cnt_ss++] = seg(y-h/2,y+h/2,x-w/2,val); ss[cnt_ss++] = seg(y-h/2,y+h/2,x+w/2,-val); Y[cnt_y++] = y-h/2; Y[cnt_y++] = y+h/2; } sort(ss,ss+cnt_ss); sort(Y,Y+cnt_y); cnt_y = unique(Y,Y+cnt_y)-Y; int ans=0; memset(cnt,0,sizeof(cnt)); memset(sum,0,sizeof(sum)); for(int i=0;i<cnt_ss-1;i++) { int ql=lower_bound(Y,Y+cnt_y,ss[i].l)-Y; int qr=lower_bound(Y,Y+cnt_y,ss[i].r)-Y-1; if(ql<=qr) update(ql,qr,ss[i].d,1,0,cnt_y-1); ans=max(ans,sum[1]); } printf("%d\n",ans); } }