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;
}

  

posted @ 2015-02-21 12:09  雪溯  阅读(268)  评论(0编辑  收藏  举报