题意:
给出平面上 个点,坐标绝对值不超过 ,求曼哈顿距离不小于 的点对共有多少?
对于点对 和 ,其曼哈顿距离即为
分析:
参考Blog:传送门
曼哈顿距离:
切比雪夫距离:
- 将一个点 的坐标变为 后,原坐标系中的曼哈顿距离 新坐标系中的切比雪夫距离
- 将一个点 的坐标变为 后,原坐标系中的切比雪夫距离 新坐标系中的曼哈顿距离
在曼哈顿距离中,距离原点为
时,构成下图:
而转化为切比雪夫距离后,距离源点为
时,构成下图:
- 应注意,在转化后,虽然 坐标发生改变,但是对应计算后的 距离并未改变;
因此,该题将曼哈顿距离转化为切比雪夫距离后,对于每一个点,只需要计算 以其为中心,边长为 的正方形区域内(不包括边缘)有多少个点 即可。
以下代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
typedef long long LL;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int MOD=1e9+7;
const int maxn=1e5+10;
int N,d,L;
vector<int> v[2*maxn];
int c[maxn*2];
int lowbit(int x)
{
return x&(-x);
}
void updata(int i,int k) //令a[i]+k
{
while(i<=4*L)
{
c[i]+=k;
i+=lowbit(i);
}
}
int query(int i) //sum[l~r]=query(r)-query(l-1)
{
int ret = 0;
while(i>0)
{
ret+=c[i];
i-=lowbit(i);
}
return ret;
}
int main()
{
scanf("%d %d %d",&N,&d,&L);
for(int i=1;i<=N;i++)
{
int x,y,xx,yy;
scanf("%d %d",&x,&y);
xx=x+y+2*L; //转化,并加上2*L将其转为正数
yy=x-y+2*L;
v[xx].push_back(yy); //v[x]中存放横坐标为x的点的纵坐标y
}
LL ans=0;
for(int x=0;x<=4*L;x++) //对每个点,仅查找其左方(正方形左半边)有多少范围内的点
{
for(auto y:v[x])
{
ans+=query(min(4*L,y+d-1))-query(max(0,y-d)); //查找范围内的点数
updata(y,1); //更新范围内的点
}
if(x-d+1>=0)
{
for(auto y:v[x-d+1]) //删除超出范围的点
updata(y,-1);
}
}
printf("%lld\n",1LL*N*(N-1)/2-ans); //N*(N-1)/2为总的点对数量
return 0;
}