题意:给定n<=100000个二维点,并且0<=x,y<=100000,求有多少个平行于坐标轴的正方形

思路:本来想hash的,但是感觉不好弄。。

后来感觉像是分块,最坏的情况就是那种x,y点稠密在一起的情况,并且x与y大致相同的情况下答案最多。。

然后就想到了跟分块很像的暴力。

对于每个点,用vx[x]记录有p.x==x的点的y,用vy[y]记录p.y==y的x

那么对于每个vx[], vy[]排序。。

接着对于每个点我们统计以它为右上角的正方形。。

那么对于每个点(x, y),我们二分查找x处于vy[y]的位置ty,我们二分查找y处于vx[x]的位置tx

那么如果tx<ty,我们直接统计vx[x][0]~vx[x][tx-1]的所有y是否有符合的

每次判断可以通过使用二分查找其他点是否存在。。

如果tx>=ty则统计vy[y][0]~vy[y][ty-1]的所有y是否符合。方法类似。

这样最坏情况下应该跟分块的复杂度差不多吧(不会证明)

code:

 #include <bits/stdc++.h>
#define M0(x) memset(x, 0, sizeof(x))
#define MP make_pair
#define PB push_back
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;
#define x first
#define y second
const int maxn = ;
pair<int, int> p[maxn];
vector<int> vx[maxn], vy[maxn];
int n, m; void solve(){
int mx = , my = ;
repf(i, , n){
scanf("%d%d", &p[i].x, &p[i].y);
mx = max(p[i].x, mx);
my = max(p[i].y, my);
}
repf(i, , mx) vx[i].clear();
repf(i, , my) vy[i].clear();
repf(i, , n){
vx[p[i].x].PB(p[i].y);
vy[p[i].y].PB(p[i].x);
}
repf(i, , mx) sort(vx[i].begin(), vx[i].end());
repf(i, , my) sort(vy[i].begin(), vy[i].end());
int ans = ;
int tx, ty, x, y, t2, t3, d, nx, ny;
repf(i, , n){
x = p[i].x, y = p[i].y;
tx = lower_bound(vx[x].begin(), vx[x].end(), y) - vx[x].begin();
ty = lower_bound(vy[y].begin(), vy[y].end(), x) - vy[y].begin();
if (tx < ty){
t2 = ty;
for (int j = tx-; j >= ; --j){
d = y - vx[x][j];
nx = x - d;
t2 = lower_bound(vy[y].begin(), vy[y].end(), nx) - vy[y].begin();
if (vy[y][t2] == nx){
t3 = lower_bound(vx[nx].begin(), vx[nx].end(), vx[x][j]) - vx[nx].begin();
if (vx[nx][t3] == vx[x][j]) ++ans;
}
}
continue;
}
// t2 = tx;
for (int j = ty-; j >= ; --j){
d = x - vy[y][j];
ny = y - d;
t2 = lower_bound(vx[x].begin(), vx[x].end(), ny) - vx[x].begin();
if (vx[x][t2] == ny){
t3 = lower_bound(vy[ny].begin(), vy[ny].end(), vy[y][j]) - vy[ny].begin();
if (vy[ny][t3] == vy[y][j]) ++ans;
}
}
}
cout << ans << endl;
} int main(){
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
while (scanf("%d", &n) != EOF){
solve();
}
return ;
}
05-11 04:49