[BZOJ3543]-[ONTAK2010]Garden-阈值法

说在前面

并没有什么想说的,但是要保持格式=w=


题目

BZOJ3543传送门

题目大意

给出平面上 n 个点,询问由这些点组成的正方形有多少个,且正方形的边与坐标轴平行
范围: n 10 5 | x i | , | y i | 10 6

输入输出格式

输入格式:
第一行一个整数 n
接下来 n 行,每行两个整数 x , y 描述一个点的坐标

输出格式:
输出一个整数表示答案


解法

这是一道典型阈值法的题
因为正方形数量最多 n n 个(就是全部挤在一起的情况),所以可以暴力统计

如何暴力?因为是正方形,所以只需要确定两个点,另外的两个点hash查找存在性即可
在同一个 x 坐标中,点数小于 n 的我们称之为「小行」,否则称之为「大行」
首先如果两个点都在「小行」可以直接暴力,复杂度 n n
然后是「大行」,因为大行最多只有 n 个,所以我们把「大行」的点再单独提出来,按照 y 坐标分组,不难发现所有的列全都是「小列」,然后同样的搞一搞即可


下面是代码

#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() ;
}

猜你喜欢

转载自blog.csdn.net/izumi_hanako/article/details/80368561
今日推荐