题意:
在二维坐标系中有n个点,给定这n个点的坐标(x,y),
现在你有一个w*h的框,问最多能框到多少个点。
数据范围:n<=1e4,-2e4<=x,y<=2e4,1<=w,h<=4e4
解法:
坐标可能是负数,方便起见加上一个base变为正数
扫描线,从左到右用竖线扫描横坐标,
如果存在点(x,y),那么在x处加入这个点,在x+w+1处减去这个点.
然后问题变为在固定的横坐标x下,长度为h最多能覆盖多少个点.
发现这样还是很难快速计算,因为需要枚举端点.
一个巧妙的做法:
令线段树的每个位置y表示[y,y-h]能覆盖到的点数量,
那么考虑点(x,y)的y在哪些位置上有贡献,
显然y在[y,y+h]内有贡献,
因此对于点(x,y),将线段树的[y,y+h]位置+1
那么查询就变成查询整颗线段树的最大值
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=2e5+5;
struct Trie{
int a[maxm<<2];
int laz[maxm<<2];
void pushup(int node){
a[node]=max(a[node*2],a[node*2+1]);
}
void pushdown(int node){
if(laz[node]){
laz[node*2]+=laz[node];
laz[node*2+1]+=laz[node];
a[node*2]+=laz[node];
a[node*2+1]+=laz[node];
laz[node]=0;
}
}
void update(int st,int ed,int val,int l,int r,int node){
if(st<=l&&ed>=r){
a[node]+=val;
laz[node]+=val;
return ;
}
pushdown(node);
int mid=(l+r)/2;
if(st<=mid)update(st,ed,val,l,mid,node*2);
if(ed>mid)update(st,ed,val,mid+1,r,node*2+1);
pushup(node);
}
}t;
struct Node{
int x,y,f;
bool operator<(const Node& a)const{
if(x!=a.x)return x<a.x;
return f<a.f;
}
}e[maxm<<1];
int n,w,h;
signed main(){
while(scanf("%d",&n)!=EOF&&n>=0){
scanf("%d%d",&w,&h);
int tot=0;
int lc=1e9,rc=0;
for(int i=1;i<=n;i++){
int x,y;scanf("%d%d",&x,&y);
x+=20005,y+=20005;
lc=min(lc,y);
rc=max(rc,y);
e[++tot]={x,y,1};
e[++tot]={x+w+1,y,-1};
}
sort(e+1,e+1+tot);
int ans=0;
for(int i=1;i<=tot;i++){
int l=max(lc,e[i].y);
int r=min(rc,e[i].y+h);
t.update(l,r,e[i].f,lc,rc,1);
ans=max(ans,t.a[1]);
}
printf("%d\n",ans);
}
return 0;
}