题目链接
题目描述
茶颜悦色也太好喝了!鸡尾酒在长沙的各种茶颜悦色的店铺中流连忘返。他发现长沙有炒鸡多的茶颜悦色店,走两步就能遇到一家。
“方圆一公里能有十家茶颜悦色!”鸡尾酒感叹了起来。
于是他想到了一个问题:最密集的地方,能有多少家茶颜悦色的店?
鸡尾酒将长沙地图用一个二维平面表示,他统计出了每个茶颜悦色店铺的坐标。
他想知道,在一个边长为 kk 且底边平行于 xx 轴的正方形中,最多有多少家茶颜悦色。
若茶颜悦色恰好在正方形的边上,也算在正方形之中。
输入描述
输入第一行包含两个正整数 n,n, (n \le10{5},k≤10{9}n≤10 5 ,k≤10 9) 代表茶颜悦色店的数量和正方形的边长。
接下来 nn 行每行有两个整数,描述一家茶颜悦色店的坐标 x_{i},y_{i}x i ,y i(0 \le x_{i}, y_{i} \le 10^{9}0≤x i ,y i ≤10 9) 保证不会出现重复的坐标。
输出描述
输出一行一个正整数表示答案。
解题思路
贴官方题解:
由题设 k 为正方形边长。首先我们可以通过确定正方形的底边来
确定正方形。比如底边是由[x, y],[x + k, y]两点连成的边,那么这样的
底边可以确定一个由[x, y],[x + k, y],[x, y + k],[x + k, y + k]四个点组成的正方形。假设我
们用左下角的点[x, y]来代表这个正方形(下同)。
现在我们来考虑某个点(a,b)可以被怎样的正方形包含。那么我们
会发现,左下角的点的 x 坐标满足(a − k ≤ x ≤ a)且 y 坐标满足
(b − k ≤ y ≤ b)会包含(a,b)这个点。
我们不妨用扫描线的思想来解决这道题。我们从左到右地扫描 x
坐标,并用线段树维护当前 y 坐标上的点数量。即当目前扫描到区间
[a − k, a]时,点(a,b)对 y 坐标为[b-k,b]中的正方形有贡献。所以当
扫描到 a-k 时,将区间[b-k,b]全部+1。当扫描到 a 时,将区间对应
地-1。这样就可以描述(a,b)点对题目答案的贡献了。
具体的做法:每个点(a,b)存两遍,一遍存(a-k,b)且置 flag 为 1,
代表扫描到此点时要将区间+1,第二遍存(a,b)且置 flag 为-1,代表
扫描到此点时要将区间-1。然后按 x 坐标排序,用线段树扫描 x 坐标
即可。每次+1 之后区间查询全局最大值,更新答案。
时间复杂度O(?log2 ?)
注意:其中要用离散化,记录边的时候,左边的点flag记1,右边的记-1,这个地方wa惨我了。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=1e5+5;
struct linee
{
long long x,y,h;
int flag;
}a[N*4];
long long yy[N*4];
struct node
{
int l,r,lazy,sum;
};
node e[N*10];
int cmp(linee x,linee y)
{
if(x.x==y.x)
return x.flag>y.flag;
return x.x<y.x;
}
void build(int root,int l,int r)
{
e[root].l=l;
e[root].r=r;
e[root].lazy=e[root].sum=0;
if(e[root].l==e[root].r)
return ;
else
{
build(root*2,l,(l+r)/2);
build(root*2+1,(l+r)/2+1,r);
}
}
void updown(int root)
{
if(e[root].lazy)
{
e[root*2].lazy+=e[root].lazy;
e[root*2+1].lazy+=e[root].lazy;
e[root*2].sum+=e[root].lazy;
e[root*2+1].sum+=e[root].lazy;
e[root].lazy=0;
}
}
void update(int root,int l,int r,int v)
{
if(e[root].l>=l&&e[root].r<=r)
{
e[root].sum+=v;
e[root].lazy+=v;
return ;
}
updown(root);
int mid=(e[root].l+e[root].r)/2;
if(r<=mid)
update(root*2,l,r,v);
else
{
if(l>mid)
update(root*2+1,l,r,v);
else
{
update(root*2,l,mid,v);
update(root*2+1,mid+1,r,v);
}
}
e[root].sum=max(e[root*2].sum,e[root*2+1].sum);
}
int main()
{
int n;
long long k;
scanf("%d %lld",&n,&k);
int cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%lld %lld",&a[i].x,&a[i].y);
a[i].flag=-1;
a[i+n].x=a[i].x-k;a[i+n].y=a[i].y;
a[i+n].flag=1;
yy[cnt++]=a[i].y;
yy[cnt++]=a[i].y-k;
}
sort(a+1,a+1+2*n,cmp);
sort(yy,yy+cnt);
int m=unique(yy,yy+cnt)-yy;
build(1,0,m);
int ans=0;
for(int i=1;i<=2*n;i++)
{
int l=lower_bound(yy,yy+cnt,(a[i].y-k))-yy;
int r=lower_bound(yy,yy+cnt,a[i].y)-yy;
//printf("%d %d %d\n",l,r,a[i].flag);
update(1,l,r,a[i].flag);
if(a[i].flag==1)
{
ans=max(ans,e[1].sum);
}
}
printf("%d\n",ans);
return 0;
}