ZOJ 3521 Fairy Wars oj错误题目,计算几何,尺取法,排序二叉树,并查集 难度:2

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3521 

ATTENTION:如果用long long 减小误差,这道题只能用%lld读入

首先需要判断哪些点是相互挨着的,这样比直接维护哪些集合是冰冻住的简单

按照x为主,y为辅排序,在数组上尺取,当head与tail的x坐标相差大于l/2则把head向后移动直到x坐标满足条件,

那么对于head到tail,现在的问题就只剩下检测出哪些点之间y间距小于l/2,把它们都按照pair<y,id>加入set,那么离tail最近的两个点的y坐标就是离tail最近的,如果其中某个点满足间距小于l/2,那么就把tail和这个点放在一个并查集里,(其他的点如果满足条件,会和这两个点在一个并查集里)

最后统计一下哪些并查集是被冰冻住的,以及这些并查集中有多少点即可

#include <cstdio>

#include <cstring>

#include <set>

#include <algorithm>

using namespace std;

typedef long long ll;

typedef pair<ll,ll> P;

const int maxn=5e4+3;

int n;

ll r,l;

P pnt[maxn],o;

int par[maxn];

bool in[maxn];



ll dis(P a,P b){return (a.first-b.first)*(a.first-b.first)+(a.second-b.second)*(a.second-b.second);}



int fnd(int i){return(par[i]==i?i:(par[i]=fnd(par[i])));}

bool same(int a,int b){return fnd(a)==fnd(b);}

void unite(int a,int b){

        if(!same(a,b)){

                par[par[b]]=par[a];

        }

}





void solve(){

        set<P> st;

        int head=0;

        for(int tail=0;tail<n;tail++){

                while(2*abs(pnt[tail].first-pnt[head].first)>l){

                        st.erase(P(pnt[head].second,head));

                        head++;

                }

                set<P>::iterator it = st.insert(P(pnt[tail].second,tail)).first;

                if(it!=st.begin()){

                        it--;

//printf("s:%lld %lld\n",it->first,pnt[tail].second);

                        if(2*abs(pnt[tail].second-it->first)<=l){

                                unite(tail,it->second);

                        }

                        it++;

                }



                it++;

                if(it!=st.end()){

                        if(2*abs(it->first-pnt[tail].second)<=l){

                                unite(tail,it->second);

                        }

                }

        }

}



void output(){

        int ans=0;

        for(int i=0;i<n;i++){

                if(dis(pnt[i],o)<=r*r){

                        if(!in[fnd(i)]){

                                in[par[i]]=true;

                        }

                }

        }

        for(int i=0;i<n;i++){

                if(in[fnd(i)]){

                        ans++;

                }

        }



        printf("%d\n",ans);

}

int main(){

        while(scanf("%d%lld%lld",&n,&r,&l)==3){

                memset(in,0,sizeof(in));

                for(int i=0;i<n;i++){

                        scanf("%lld%lld",&(pnt[i].first),&(pnt[i].second));

                        par[i]=i;

                }

                scanf("%lld%lld",&(o.first),&(o.second));



                sort(pnt,pnt+n);



                solve();

                output();

        }

        return 0;

}

  

你可能感兴趣的:(AIR)