【POJ3470】Walls(线段树)(扫描线)
来源:互联网 发布:梦幻西游mac版安装教程 编辑:程序博客网 时间:2024/06/08 04:05
题目大意
本义
有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
- 【POJ3470】Walls(线段树)(扫描线)
- hdu1542 Atlantis (线段树+扫描线)
- 线段树扫描线(好)poj2482
- hdu5091(扫描线+线段树)
- poj1511 Atlantis(线段树+扫描线)
- HDU-1542(线段树+扫描线)
- hdu1542(线段树+扫描线)
- HDU1542(线段树+扫描线)
- poj 1151(线段树+扫描线)
- HDU1542 Atlantis(线段树+扫描线)
- HDU3255 Farming(线段树+扫描线)
- hdu1542 Atlantis (线段树|扫描线)
- poj 1177(线段树扫描线)
- hdu 5091 (线段树,扫描线)
- [POJ1151]Atlantis(扫描线+线段树)
- poj1151(线段树+扫描线)
- 线段树扫描线(hdu1542)
- 线段树+扫描线(基本原理)
- selenium中窗口切换和鼠标悬停的例子
- 84. Largest Rectangle in Histogram
- laravel 下载,出现错误:composer Content-Length mismatch
- Ceph 状态查询
- 将二叉搜索树转化为一个排序的双向链表
- 【POJ3470】Walls(线段树)(扫描线)
- 逻辑回归算法简介及用python实现
- ireport+springmvc实现报表预览
- 初识git
- Comet
- asp实用sub小程序
- luogu1002【2002普及】过河卒(递推)
- 7月英语总结
- JavaScript实战-DOM操作之奇偶变色表格