ZOJ 3521 Fairy Wars(扫描线)

题意:平面上有N个子弹,每个子弹的坐标已知,现在在距离点x0,y0为R的圆内,所以的子弹都会变成冰块L*L,并且在L*L范围内的所有其他子弹也会变成冰块,问,当连锁反应结束时,变成冰块的子弹数有多少。

也就是说落在子弹L/2的范围内的子弹都会结冰,也可以转化成只要边界在子弹L/4范围内的子弹会结冰,这样扫描线就可以搞定了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

typedef long long LL;
const int N=100005;

#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define MID(a,b) (a+((b-a)>>1))

struct Line
{
    LL x,y1,y2,w;
    Line(){}
    Line(LL x,LL y1,LL y2,LL w) :
        x(x),y1(y1),y2(y2),w(w) {}
    bool operator<(const Line &B)const
    {
        return x<B.x||(x==B.x&&w>B.w);
    }
};

int n,R,L,len;
int fa[N],cnt[N],vis[N];
LL X[N],Y[N],x0,y0;
vector<LL> SY;
map<LL,int> H;
vector<Line> line;

LL sqr(LL x) { return x*x; }
int find_fa(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=find_fa(fa[x]);
}
void unin(int a,int b)
{
    int x=find_fa(a);
    int y=find_fa(b);
    if(x!=y) fa[x]=y,cnt[y]+=cnt[x];
}
struct SegTree
{
    int color[N*4];
    void build(int lft,int rht,int ind)
    {
        color[ind]=0;
        if(lft!=rht)
        {
            int mid=MID(lft,rht);
            build(lft,mid,LL(ind));
            build(mid+1,rht,RR(ind));
        }
    }
    void updata(int st,int ed,int valu,int lft,int rht,int ind)
    {
        if(st<=lft&&rht<=ed)
        {
            if(valu>0) color[ind]=valu;
            else if(color[ind]==-valu) color[ind]=0;
        }
        else
        {
            int mid=MID(lft,rht);
            if(st<=mid) updata(st,ed,valu,lft,mid,LL(ind));
            if(ed> mid) updata(st,ed,valu,mid+1,rht,RR(ind));
        }
    }
    int query(int pos,int lft,int rht,int ind)
    {
        if(color[ind]!=0) return color[ind];
        if(lft==rht) return 0;

        int mid=MID(lft,rht);
        if(pos<=mid) return query(pos,lft,mid,LL(ind));
        else return query(pos,mid+1,rht,RR(ind));
    }
}seg;

int main()
{
    while(scanf("%d%d%d",&n,&R,&L)!=EOF)
    {
        line.clear(); SY.clear(); H.clear();
        for(int i=0;i<N;i++) fa[i]=i,cnt[i]=1,vis[i]=0;

        for(int i=1;i<=n;i++)
        {
            LL a,b; scanf("%lld%lld",&a,&b);
            X[i]=a;     Y[i]=b;
            SY.push_back(b*4-L);
            SY.push_back(b*4+L);
            line.push_back(Line(a*4-L,b*4-L,b*4+L,i));
            line.push_back(Line(a*4+L,b*4-L,b*4+L,-i));
        }

        sort(line.begin(),line.end());

        sort(SY.begin(),SY.end());
        SY.erase(unique(SY.begin(),SY.end()),SY.end());
        len=(int)SY.size();
        for(int i=0;i<len;i++) H[SY[i]]=i;

        seg.build(0,len-1,1);
        for(int i=0;i<(int)line.size();i++)
        {
            int y1=H[line[i].y1];
            int y2=H[line[i].y2];
            int w=line[i].w;

            if(w>0)
            {
                int tmp1=seg.query(y1,0,len-1,1);
                int tmp2=seg.query(y2,0,len-1,1);
                if(tmp1!=0) unin(tmp1,w);
                if(tmp2!=0) unin(tmp2,w);
            }
            seg.updata(y1,y2,w,0,len-1,1);
        }

        scanf("%lld%lld",&x0,&y0);

        int res=0;
        for(int i=1;i<=n;i++)
        {
            LL tmp1=sqr(X[i]-x0);
            LL tmp2=sqr(Y[i]-y0);
            if(tmp1+tmp2<=sqr(R)&&vis[find_fa(i)]==0)
            {
                vis[find_fa(i)]=1;
                res+=cnt[find_fa(i)];
            }
        }
        printf("%d\n",res);
    }
    return 0;
}


你可能感兴趣的:(ZOJ 3521 Fairy Wars(扫描线))