BZOJ3543: [ONTAK2010]Garden

http://www.lydsy.com/JudgeOnline/problem.php?id=3543

  首先明确两点,对于一个平行于坐标轴的正方形,只需要确定的一条边就可以,比如说下边或者右边。还有一个结论:n个点的二维点集的平行坐标轴的正方形个数是O(n√n)的。

  所以我们大概就明白了这题是需要暴力统计的。

  将横坐标相同的点放进同一个集合,点数>√n的称为大集合,否则是小集合。将读入的点丢进hash里。

  枚举每个集合:

    对于大集合,易知不超过√n个,每个就枚举其左侧的每个点,那么就确定了下边界,hash判定一下另外三个点的存在性即可。复杂度O(n√n)。

    对于小集合,暴力枚举集合内的点对来确定右边,hash判定。总复杂度不超过O(n√n)。

#include<bits/stdc++.h>
#include<tr1/unordered_set>
using namespace std;
const int maxn=100010,maxy=2000010;
struct point{
    int x,y;
    point(): x(0),y(0) { }
    point(int x_,int y_): x(x_),y(y_) { }
    bool operator==(const point &b)const{
        return x==b.x && y==b.y;
    }
}a[maxn];
struct hasher{
    long long operator()(const point &t)const{
        const long long seed=23333;
        return t.x*seed+t.y;
    }
};
std::tr1::unordered_set<point,hasher> t;
vector<int> heavy;
int l[maxy],r[maxy]; bool flag[maxy];
int n,S;
 
inline bool cmp_y(const point &a,const point &b){
    return a.y<b.y || (a.y==b.y && a.x<b.x);
}
void init(){
    scanf("%d",&n),S=sqrt(n)*2;
    t.clear(),heavy.clear();
    for(int i=1;i<=n;++i){
        scanf("%d%d",&a[i].x,&a[i].y);
        a[i].y+=1e6,t.insert(a[i]);
    }
    sort(a+1,a+n+1,cmp_y);
}
 
void solve(){
    memset(l,-1,sizeof(l));
    memset(r,-1,sizeof(r));
    memset(flag,false,sizeof(flag));
    for(int u=1,v=1;u<=n;u=v){
        while(v<=n && a[v].y==a[u].y) ++v;
        l[a[u].y]=u,r[a[u].y]=v;
        if(v-u>S) heavy.push_back(a[u].y),flag[a[u].y]=true;
    }
    int ans=0;
    for(int i=1,x,y,d;i<=n;++i){
        x=a[i].x,y=a[i].y;
        if(flag[y]){
            for(int j=0;j<heavy.size();++j){
                d=heavy[j]-y; if(d<=0) continue;
                if(t.count(point(x,y+d)) && t.count(point(x+d,y)) && t.count(point(x+d,y+d)))
                    ++ans;
            }
        }
        else{
            for(int j=i+1;j<r[y];++j){
                d=a[j].x-x; if(!d) continue;
                if(t.count(point(x,y+d)) && t.count(point(x+d,y+d)))
                    ++ans;
                if(y-d>=0 && flag[y-d] && t.count(point(x,y-d)) && t.count(point(x+d,y-d)))
                    ++ans;
            }
        }
    }
    printf("%d\n",ans);
}
 
int main(){
    init();
    solve();
    return 0;
}
my code

 

posted @ 2015-08-11 09:47  iamCYY  阅读(504)  评论(0编辑  收藏  举报