【POJ3470】Walls(线段树)(扫描线)

题目大意

本义

有n堵墙,m只智障鸟,给出墙端点坐标,鸟坐标,墙一定是平行于坐标轴,横着或竖着,每只鸟都会选一个离自己最近的墙撞过去,鸟一定是平行于坐标轴飞行,只能横着或竖着飞,问每堵墙被几只鸟撞过。

题目没说的坑爹问题:
  • 坐标可以为负数
  • 坐标可能大于INT_MAX
  • 鸟可能初始就卡在某堵墙里(坐标在墙的端点或连线上,给这堵墙算一次)
  • 鸟可以在墙的延长线上,可以直接顺着延长线撞到墙上
  • 鸟不会有多个墙来选择
  • 鸟有可能撞不到任何墙

题解

扫描线,从左往右时,视为鸟固定往左飞,用线段树记录这根扫描线遇到的墙,标记墙的领土,如下图。
扫描线
灰色的扫描线向右扫描,扫描线上标有颜色的是线段树标记的墙的领土,如果此时碰到鸟,则鸟一直向右飞碰到的墙可直接用线段树查询。如马上碰到右边的黑点,查询线段树,就可得知它将撞到红色墙。继续扫描过程中,碰到黄色墙,将在对应线段树区域标为黄色,然后灰色点就可以撞到黄色墙。注意,横着的绿色墙也需要标记,在线段树上那一个点被标为绿色。
具体实现细节见代码,有注释。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=200010;
struct Bird
{
    int id;
    long long x,y;
    inline void read()
    {scanf("%lld%lld",&x,&y);}
};
bool Bird_cmpx_g(Bird a,Bird b)
{return a.x<b.x||(a.x==b.x&&a.y<b.y);}
bool Bird_cmpy_g(Bird a,Bird b)
{return a.y<b.y||(a.y==b.y&&a.x<b.x);}
bool Bird_cmpx_l(Bird a,Bird b)
{return a.x>b.x||(a.x==b.x&&a.y>b.y);}
bool Bird_cmpy_l(Bird a,Bird b)
{return a.y>b.y||(a.y==b.y&&a.x>b.x);}
struct Wall
{
    int id;
    Bird a,b;
    inline void read()
    {a.read();b.read();}
    inline bool mode()
    {return a.x==b.x;}
};
bool Wall_cmpx_g(Wall a,Wall b)
{return Bird_cmpx_g(a.a,b.a);}
bool Wall_cmpy_g(Wall a,Wall b)
{return Bird_cmpy_g(a.a,b.a);}
bool Wall_cmpx_l(Wall a,Wall b)
{return Bird_cmpx_l(a.a,b.a);}
bool Wall_cmpy_l(Wall a,Wall b)
{return Bird_cmpy_l(a.a,b.a);}
class SegTree
{
    static int N;
    int wid[MAXN*12];
public:
    inline void Init(int n)
    {
        memset(wid,0,sizeof wid);
        N=n;
    }
    void Insert(int L,int R,int val,int id=1,int l=0,int r=N)
    {
        if(r<L||R<l)
            return;
        if(L<=l&&r<=R)
        {
            wid[id]=val;
            return;
        }
        if(wid[id]!=-1)
            wid[id*2]=wid[id*2+1]=wid[id];
        Insert(L,R,val,id*2,l,(l+r)/2);
        Insert(L,R,val,id*2+1,(l+r)/2+1,r);
        if(wid[id*2]==-1||wid[id*2+1]==-1||wid[id*2]!=wid[id*2+1])
            wid[id]=-1;
    }
    int Query(int pos,int id=1,int l=0,int r=N)
    {
        if(r<pos||pos<l)
            return -1;
        if(wid[id]!=-1)
            return wid[id];
        int q1=Query(pos,id*2,l,(l+r)/2);
        int q2=Query(pos,id*2+1,(l+r)/2+1,r);
        if(q1==-1)return q2;
        return q1;
    }
};
Wall wall[MAXN];
Bird bird[MAXN];
long long mapx[MAXN*3],mapy[MAXN*3];
int x_cnt,y_cnt;
long long dis[MAXN];
int ans[MAXN],hitid[MAXN];
SegTree ST;
int SegTree::N;
int main()
{
    int N,M;
    scanf("%d%d",&N,&M);
    //输入,初始化,记录x,y,用于离散化
    for(int i=1;i<=N;i++)
    {
        wall[i].read();
        wall[i].id=i;
        mapx[x_cnt++]=wall[i].a.x;
        mapx[x_cnt++]=wall[i].b.x;
        mapy[y_cnt++]=wall[i].a.y;
        mapy[y_cnt++]=wall[i].b.y;
    }
    for(int i=1;i<=M;i++)
    {
        bird[i].read();
        bird[i].id=i;
        mapx[x_cnt++]=bird[i].x;
        mapy[y_cnt++]=bird[i].y;
    }
    memset(dis,0x7F,sizeof dis);
    //排序,离散化墙,鸟的坐标
    sort(mapx,mapx+x_cnt);
    sort(mapy,mapy+y_cnt);
    for(int i=1;i<=N;i++)
    {
        wall[i].a.x=lower_bound(mapx,mapx+x_cnt,wall[i].a.x)-mapx;
        wall[i].a.y=lower_bound(mapy,mapy+y_cnt,wall[i].a.y)-mapy;
        wall[i].b.x=lower_bound(mapx,mapx+x_cnt,wall[i].b.x)-mapx;
        wall[i].b.y=lower_bound(mapy,mapy+y_cnt,wall[i].b.y)-mapy;
    }
    for(int i=1;i<=M;i++)
    {
        bird[i].x=lower_bound(mapx,mapx+x_cnt,bird[i].x)-mapx;
        bird[i].y=lower_bound(mapy,mapy+y_cnt,bird[i].y)-mapy;
    }
    int wid,bid;
    //设置墙同一直线总是坐标小的在前,方便排序
    for(int i=1;i<=N;i++)
    {
        if(wall[i].mode()&&wall[i].a.y>wall[i].b.y)
            swap(wall[i].a.y,wall[i].b.y);
        if(!wall[i].mode()&&wall[i].a.x>wall[i].b.x)
            swap(wall[i].a.x,wall[i].b.x);
    }
    //初始化,按x从小到大排序
    wid=bid=1;
    ST.Init(3*N);
    sort(wall+1,wall+N+1,Wall_cmpx_g);
    sort(bird+1,bird+M+1,Bird_cmpx_g);
    //扫描线,从左到右,从下到上,鸟向左撞
    while(wid<=N||bid<=M)
    {
        //添加墙的地盘
        if(wid<=N&&(bid>M||Bird_cmpx_g(wall[wid].a,bird[bid])))
        {
            ST.Insert(wall[wid].a.y,wall[wid].b.y,wid);
            wid++;
        }
        //更新鸟的答案
        else if(bid<=M)
        {
            int qid=ST.Query(bird[bid].y);
            if(qid!=0)
            {
                long long d=max(0LL,mapx[bird[bid].x]-mapx[wall[qid].b.x]);
                if(d<dis[bird[bid].id])
                {
                    if(dis[bird[bid].id]!=0x7F7F7F7F7F7F7F7FLL)
                        ans[hitid[bird[bid].id]]--;
                    ans[wall[qid].id]++;
                    dis[bird[bid].id]=d;
                    hitid[bird[bid].id]=wall[qid].id;
                }
            }
            bid++;
        }
    }
    //初始化,按y从小到大排序
    wid=bid=1;
    ST.Init(3*N);
    sort(wall+1,wall+N+1,Wall_cmpy_g);
    sort(bird+1,bird+M+1,Bird_cmpy_g);
    //扫描线,从下到上,从左到右,鸟向下撞
    while(wid<=N||bid<=M)
    {
        //添加墙的地盘
        if(wid<=N&&(bid>M||Bird_cmpy_g(wall[wid].a,bird[bid])))
        {
            ST.Insert(wall[wid].a.x,wall[wid].b.x,wid);
            wid++;
        }
        //更新鸟的答案
        else if(bid<=M)
        {
            int qid=ST.Query(bird[bid].x);
            if(qid!=0)
            {
                long long d=max(0LL,mapy[bird[bid].y]-mapy[wall[qid].b.y]);
                if(d<dis[bird[bid].id])
                {
                    if(dis[bird[bid].id]!=0x7F7F7F7F7F7F7F7FLL)
                        ans[hitid[bird[bid].id]]--;
                    ans[wall[qid].id]++;
                    dis[bird[bid].id]=d;
                    hitid[bird[bid].id]=wall[qid].id;
                }
            }
            bid++;
        }
    }
    //设置墙同一直线总是坐标大的在前,方便排序
    for(int i=1;i<=N;i++)
    {
        if(wall[i].mode()&&wall[i].a.y<wall[i].b.y)
            swap(wall[i].a.y,wall[i].b.y);
        if(!wall[i].mode()&&wall[i].a.x<wall[i].b.x)
            swap(wall[i].a.x,wall[i].b.x);
    }
    //初始化,按x从大到小排序
    wid=bid=1;
    ST.Init(3*N);
    sort(wall+1,wall+N+1,Wall_cmpx_l);
    sort(bird+1,bird+M+1,Bird_cmpx_l);
    //扫描线,从右到左,从上到下,鸟向右撞
    while(wid<=N||bid<=M)
    {
        //添加墙的地盘
        if(wid<=N&&(bid>M||Bird_cmpx_l(wall[wid].a,bird[bid])))
        {
            ST.Insert(wall[wid].b.y,wall[wid].a.y,wid);
            wid++;
        }
        //更新鸟的答案
        else if(bid<=M)
        {
            int qid=ST.Query(bird[bid].y);
            if(qid!=0)
            {
                long long d=max(0LL,mapx[wall[qid].b.x]-mapx[bird[bid].x]);
                if(d<dis[bird[bid].id])
                {
                    if(dis[bird[bid].id]!=0x7F7F7F7F7F7F7F7FLL)
                        ans[hitid[bird[bid].id]]--;
                    ans[wall[qid].id]++;
                    dis[bird[bid].id]=d;
                    hitid[bird[bid].id]=wall[qid].id;
                }
            }
            bid++;
        }
    }
    //初始化,按y从大到小排序
    wid=bid=1;
    ST.Init(3*N);
    sort(wall+1,wall+N+1,Wall_cmpy_l);
    sort(bird+1,bird+M+1,Bird_cmpy_l);
    //扫描线,从上到下,从右到左,鸟向下撞
    while(wid<=N||bid<=M)
    {
        //添加墙的地盘
        if(wid<=N&&(bid>M||Bird_cmpy_l(wall[wid].a,bird[bid])))
        {
            ST.Insert(wall[wid].b.x,wall[wid].a.x,wid);
            wid++;
        }
        //更新鸟的答案
        else if(bid<=M)
        {
            int qid=ST.Query(bird[bid].x);
            if(qid!=0)
            {
                long long d=max(0LL,mapy[wall[qid].b.y]-mapy[bird[bid].y]);
                if(d<dis[bird[bid].id])
                {
                    if(dis[bird[bid].id]!=0x7F7F7F7F7F7F7F7FLL)
                        ans[hitid[bird[bid].id]]--;
                    ans[wall[qid].id]++;
                    dis[bird[bid].id]=d;
                    hitid[bird[bid].id]=wall[qid].id;
                }
            }
            bid++;
        }
    }
    //输出
    for(int i=1;i<=N;i++)
        printf("%d\n",ans[i]);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值