这题算是经典的扫描线算法题目了,
稍加分析,对任意一点(x,y) 要使长W宽H的右上角为(a,b)的的矩形包含该点,那么(a,b)必须在矩形A(左下角(x,y),右上角(x+W,y+H))范围内。
由此把每个点抽象为一个矩形,让这些矩形相交,求一点使得被覆盖的次数最大。
那么把每个矩形转换为左右两条边,加入扫描队列,有线段树维护区间最大值即可。
还有点,即点的实段化,在线段树中,将矩形的每条边抽象为一个个连续的整点。
#include <map> #include <set> #include <cstdio> #include <vector> #include <cmath> #include <cctype> #include <deque> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define rep(i,n) for(int (i)=0;(i)<n;(i)++) #define Rep(i,n) for(int (i)=1;(i)<=n;(i)++) const int N = 111111; const int lim = 100000; const int add = 20111; int Max[N<<2],col[N<<2]; void build(int l,int r,int rt){ Max[rt] = col[rt] =0; if( l == r) return ; int m = (l+r)>>1; build(lson); build(rson); } void push_up(int l,int r,int rt){ Max[rt] = max(Max[rt<<1],Max[rt<<1|1]); } void push_down(int l,int r,int rt){ if(col[rt]!=0){ col[rt<<1]+=col[rt]; col[rt<<1|1]+=col[rt]; Max[rt<<1] += col[rt]; Max[rt<<1|1]+=col[rt]; col[rt] = 0; return ; } } void update(int l,int r,int rt,int L,int R,int v){ if(L<=l&&r<=R){ col[rt] += v; Max[rt] += v; return ; } push_down(l,r,rt); int m=(l+r)>>1; if(L<=m) update(lson,L,R,v); if(R> m) update(rson,L,R,v); push_up(l,r,rt); } int n,W,H; struct seg{ int h1,h2,x,v; seg(){} seg(int x,int h1,int h2,int v): x(x),h1(h1),h2(h2),v(v){} bool operator<(const seg& rhs) const{ if(x!=rhs.x) return x<rhs.x; return v>rhs.v; } }s[N<<1]; int main() { while(scanf("%d",&n)==1&& n>=0){ scanf("%d %d",&W,&H); int m=1,l=N,r=-N; for(int i=1;i<=n;i++){ int a,b,c,d; scanf("%d %d",&a,&b); a+=add; b+=add; c = a + W, d= b + H; s[m++] = seg(a,b,d,1); s[m++] = seg(c,b,d,-1); l = min(l,a); r = max(r,c); } sort(s+1,s+m); int res = 0; if(n) build(1,lim,1); for(int i=1;i<m;i++){ update(1,lim,1,s[i].h1,s[i].h2,s[i].v); res = max(res,Max[1]); } printf("%d\n",res); } return 0; }