说在前面
并没有什么想说的,但是要保持格式=w=
题目
题目大意
给出平面上
个点,询问由这些点组成的正方形有多少个,且正方形的边与坐标轴平行
范围:
,
输入输出格式
输入格式:
第一行一个整数
接下来
行,每行两个整数
描述一个点的坐标
输出格式:
输出一个整数表示答案
解法
这是一道典型阈值法的题
因为正方形数量最多
个(就是全部挤在一起的情况),所以可以暴力统计
如何暴力?因为是正方形,所以只需要确定两个点,另外的两个点hash查找存在性即可
在同一个
坐标中,点数小于
的我们称之为「小行」,否则称之为「大行」
首先如果两个点都在「小行」可以直接暴力,复杂度
然后是「大行」,因为大行最多只有
个,所以我们把「大行」的点再单独提出来,按照
坐标分组,不难发现所有的列全都是「小列」,然后同样的搞一搞即可
下面是代码
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int N ;
long long ans ;
struct Point{
int x , y ;
int GetHash(){ return 233 * x + 7 * y ; }
void read(){ scanf( "%d%d" , &x , &y ) ; }
bool operator == ( const Point &A ) const {
return x == A.x && y == A.y ;
}
bool operator < ( const Point &A ) const {
return y < A.y || ( y == A.y && x < A.x ) ;
}
bool operator !=( const Point &A ) const {
return !( A == *this ) ;
}
Point UP( int delta ){ return ( Point ){ x , y + delta } ; }
Point RG( int delta ){ return ( Point ){ x + delta , y } ; }
} p[100005] ;
struct HashTable{
int head[262144] , pre[100007] , tp ;
Point p[100005] ;
void clear(){
memset( head , 0 , sizeof( head ) ) ;
tp = 0 ;
}
void Insert( Point P ){
int id = P.GetHash()&262143 ;
for( int i = head[id] ; i ; i = pre[i] )
if( p[i] == P ) return ;
pre[++tp] = head[id] , head[id] = tp ;
p[tp] = P ;
}
bool Query( Point P ){
int id = P.GetHash()&262143 ;
for( int i = head[id] ; i ; i = pre[i] )
if( p[i] == P ) return true ;
return false ;
}
} Hs , HsBig ;
bool cmpx( const Point &A , const Point &B ){
return A.x < B.x || ( A.x == B.x && A.y < B.y ) ;
}
int st[100005] , ed[100005] , id_c ;
void preWork(){
sort( p + 1 , p + N + 1 ) ; p[0].y = -0x3f3f3f3f ;
for( int i = 1 ; i <= N ; i ++ )
if( p[i].y != p[i-1].y )
ed[id_c] = i - 1 , st[++id_c] = i ;
ed[id_c] = N ;
}
void solve(){
int threshold = sqrt( N ) ;
register int i , j , k , R , d , pt ;
for( i = 1 ; i <= id_c ; i ++ )
if( ed[i] - st[i] + 1 > threshold )
for( j = st[i] , R = ed[i] ; j <= R ; j ++ )
HsBig.Insert( p[j] ) ;
for( i = 1 ; i <= id_c ; i ++ ){
if( ed[i] - st[i] + 1 > threshold ) continue ;
for( j = st[i] , R = ed[i] ; j <= R ; j ++ )
for( k = j + 1 ; k <= R ; k ++ ){
d = p[k].x - p[j].x ;
if( Hs.Query( p[k].UP( d ) ) && Hs.Query( p[j].UP( d ) ) ) ans ++ ;
if( HsBig.Query( p[k].UP(-d ) ) && HsBig.Query( p[j].UP(-d ) ) ) ans ++ ;
}
} N = 0 ;
for( i = 1 ; i <= id_c ; i ++ )
if( ed[i] - st[i] + 1 > threshold )
for( j = st[i] , R = ed[i] ; j <= R ; j ++ ) p[++N] = p[j] ;
sort( p + 1 , p + N + 1 , cmpx ) , p[0].x = -0x3f3f3f3f ;
for( i = 1 , pt = 2 ; i <= N ; i = pt , pt ++ ){
while( pt <= N && p[pt].x == p[pt-1].x ) pt ++ ;
for( j = i ; j < pt ; j ++ )
for( k = j + 1 ; k < pt ; k ++ ){
d = p[k].y - p[j].y ;
if( HsBig.Query( p[k].RG( d ) ) && HsBig.Query( p[j].RG( d ) ) ) ans ++ ;
}
}
printf( "%lld" , ans ) ;
}
int main(){
scanf( "%d" , &N ) ;
for( int i = 1 ; i <= N ; i ++ )
p[i].read() , Hs.Insert( p[i] ) ;
preWork() ; solve() ;
}