先切一道紫题
洛谷P4648
题意:在一维、二维、三维(三种情况)统计曼哈顿距离小于等于D的点对数很有意思的一道题
分类讨论一下
一维:
滑动窗口模版题
二维:
二维曼哈顿距离转切比雪夫距离️
根据切比雪夫距离的性质,可以一维滑动窗口,一维区间求和(用数据结构维护一下)
这里有个小细节,因为区间的左端点可能为负数,需要加上一个大数再放进bit里
三维:
同样先转换一下距离(三维转成了四维),然后一维滑动窗口
剩下三维就是要统计边长为d的正方体内的点数
直接三维树状数组硬莽
记得离散化
再加上三维容斥
就完美结束了
◽
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll B,n,Dis,M;
ll a[100010];
struct Point{
ll x,y;
}b[100010];
struct FourD{
ll A,B,C,D;
}c[100010];
bool cmpX(const Point& a,const Point& b){
return a.x < b.x;
}
bool cmpA(const FourD& a,const FourD& b){
return a.A < b.A;
}
ll bit[200010];
ll LSB(ll i){
return i & (-i);
}
const ll twoM = 75010;
ll psq(ll i){
ll res = 0;
i = min(i,twoM * 2 - 1LL);
for( ; i > 0; i -= LSB(i)) res += bit[i];
return res;
}
void add(ll i,ll len){
for( ; i < twoM * 2; i += LSB(i)){
bit[i] += len;
}
}
ll Bit[310][310][310];
const ll thrM = 100;
void upd(ll x,ll y,ll z,ll len){
for(ll i = x; i < thrM * 3; i += LSB(i)){
for(ll j = y; j < thrM * 3; j += LSB(j)){
for(ll k = z; k < thrM * 3; k += LSB(k)){
Bit[i][j][k] += len;
}
}
}
}
ll Psq(ll x,ll y,ll z){
ll res = 0;
x = min(x,thrM * 3 - 1LL);
y = min(y,thrM * 3 - 1LL);
z = min(z,thrM * 3 - 1LL);
for(int i = x; i > 0; i -= LSB(i)){
for(int j = y; j > 0; j -= LSB(j)){
for(int k = z; k > 0; k -= LSB(k)){
res += Bit[i][j][k];
}
}
}
return res;
}
ll query(ll x1,ll x2,ll y1,ll y2,ll z1,ll z2){
//三维容斥
ll res = Psq(x2,y2,z2);
res -= Psq(x1,y2,z2) + Psq(x2,y1,z2) + Psq(x2,y2,z1);
res += Psq(x1,y1,z2) + Psq(x1,y2,z1) + Psq(x2,y1,z1);
res -= Psq(x1,y1,z1);
return res;
}
int main(){
scanf("%lld %lld %lld %lld",&B,&n,&Dis,&M);
if(B == 1){ //单调队列模板
for(ll i = 1; i <= n; i++){
scanf("%lld",&a[i]);
}
sort(a + 1,a + n + 1); //排序
ll ans = 0;
ll l = 1;
for(ll i = 1; i <= n; i++){
while(l < i && a[i] - a[l] > Dis) l++; //没用的不要
ans += i - l; //在范围里的都行
}
printf("%lld",ans);
}
else if(B == 2){
for(ll i = 1,x,y; i <= n; i++){
scanf("%lld %lld",&x,&y);
b[i].x = x + y,b[i].y = x - y; //距离的转换
}
sort(b + 1,b + n + 1,cmpX); //排序
ll ans = 0;
ll l = 1;
for(ll i = 1; i <= n; i++){
while(l < i && b[i].x - b[l].x > Dis) add(b[l].y + M,-1),l++; //没用的不要
ans += psq(b[i].y + Dis + M) - psq(b[i].y - Dis - 1 + M); //在范围里的都行
add(b[i].y + M,1); //把自己加进去
}
printf("%lld",ans);
}
else{
for(ll i = 1,x,y,z; i <= n; i++){
scanf("%lld %lld %lld",&x,&y,&z);
c[i].A = x + y + z;
c[i].B = x + y - z;
c[i].C = x - y + z;
c[i].D = -x + y + z;
}
sort(c + 1,c + n + 1,cmpA);
ll ans = 0;
ll l = 1;
for(ll i = 1; i <= n; i++){
while(l < i && c[i].A - c[l].A > Dis){
upd(c[l].B + M,c[l].C + M,c[l].D + M,-1); //三维中没用的扔掉
l++;
}
ans += query(c[i].B - Dis - 1 + M,c[i].B + Dis + M,c[i].C - Dis - 1 + M,c[i].C + Dis + M,c[i].D - Dis - 1 + M,c[i].D + Dis + M);
//硬莽三维
upd(c[i].B + M,c[i].C + M,c[i].D + M,1);
}
printf("%lld",ans);
}
return 0;
}