一、题面

POJ3470

二、分析

POJ感觉是真的老了。

这题需要一些预备知识:扫描线,离散化,线段树。线段树是解题的关键,因为这里充分利用了线段树区间修改的高效性,再加上一个单点查询。

为什么需要离散化?

坐标太分散了,据说可以到 long long,但是就这么多个点,所以离散化一下,方便处理。

为什么用扫描线算法?

用扫描线,可以方便的求出一个bird到wall的距离,因为是顺着一个方向扫的(这题需要从四个方向扫),所以保证了准确性和高效性。

为什么用线段树?

用线段树非常明显,因为墙有这么多,并且结合扫描线,墙可能会有重叠部分,而线段树的lazy标记用法刚好可以完美的使用。

然后就是一些思维方面的了,因为bird可以朝4个方向飞,所以需要从4个方向扫,如果不从4个方向扫,每次处理一个bird非常不好处理。

然后就是写代码的时候要细心,可能有很多细节问题。

三、AC代码

 #include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <cstring>
#include <cmath>
using namespace std; #define Lson(x) (x<<1) //左儿子
#define Rson(x) (x<<1|1) //左儿子
#define Mid(l, r) ( (l+r)>>1 )
#define LL long long
const int MAXN = 2e5 + ;
int N, M; //N is the number of wall
int ans[MAXN];
vector<LL> cor_x, cor_y;
struct Wall
{
LL x1, y1;
LL x2, y2;
}W[MAXN];
struct Bird
{
LL x, y;
}B[MAXN];
struct Dist
{
int id;
LL dist;
Dist()
{
//这里必须用long long 的无穷大,因为给的数据会超过int
//找这个WA点找了很久
dist = __LONG_LONG_MAX__;
}
}D[MAXN];
enum Type
{
WALL, BIRD
}; struct Object //处理对象
{
Type type;
int id; //bird's or wall's id
int x, y1, y2;
Object(int x, int y1, int y2, int id, Type type):x(x),y1(y1),y2(y2),id(id),type(type){}
bool operator < (const Object &t)const
{
return x < t.x;
}
}; struct SegTree
{
//Value的值表示线段树维护区间的墙的id
int Left[MAXN<<], Right[MAXN<<], Value[MAXN<<];
//线段树初始化
void init(int p, int l, int r)
{
Left[p] = l;
Right[p] = r;
Value[p] = ;
if(l == r)
return;
init(Lson(p), l, Mid(l, r));
init(Rson(p), Mid(l, r) + , r);
}
//出现了墙,则维护区间
void update(int p, int l, int r, int id)
{
if(Left[p] == l && Right[p] == r)
{
Value[p] = id;
return;
}
if(Value[p] > )
{
Value[Lson(p)] = Value[p];
Value[Rson(p)] = Value[p];
Value[p] = ; //一定记得清0
}
// int mid = Mid(l, r);
int mid = Mid(Left[p], Right[p]);
if(l > mid)
{
update(Rson(p), l, r, id);
}
else if(r <= mid)
{
update(Lson(p), l, r, id);
}
else
{
update(Lson(p), l, mid, id);
update(Rson(p), mid + , r, id);
}
}
//出现了bird, 在线段树中寻找合适的wall被撞
// loc 如果是沿x轴飞,那么loc应该是y值,只有这样才能保证撞的有效
int find(int p, int loc)
{
if(Left[p] == Right[p] && Left[p] == loc)
return Value[p];
if(Value[p] > )
{
Value[Lson(p)] = Value[p];
Value[Rson(p)] = Value[p];
Value[p] = ; //一定记得清0
}
int mid = Mid(Left[p], Right[p]);
if(loc > mid)
{
return find(Rson(p), loc);
}
else
{
return find(Lson(p), loc);
}
}
}STree; //计算距离
LL cal_dis(bool dir, int x1, int x2)
{
LL d1, d2;
if(dir)
{
d1 = cor_x[x1 - ];
d2 = cor_x[x2 - ];
}
else
{
d1 = cor_y[x1 - ];
d2 = cor_y[x2 - ];
}
d1 = d1 - d2;
if(d1 < )
return -d1;
else
return d1;
} void scan(const vector<Object> &arr, bool dir) //dir表示方向
{
STree.init(, , max(cor_x.size(), cor_y.size()) + );
vector<Object>::const_iterator itr;
for(itr = arr.begin(); itr != arr.end(); itr++)
{
if(itr->type == WALL)
{
STree.update(, itr->y1, itr->y2, itr->id);
}
else
{
int pos = STree.find(, itr->y1); if(pos)
{//一定要保证墙存在!
LL len;
if(dir) // dir = 1 表示沿x轴方向
//len = cal_dis(dir, itr->x, W[pos].x1);
len = min( cal_dis(true, W[pos].x1, itr->x), cal_dis(true, W[pos].x2, itr->x) ); else
//len = cal_dis(dir, itr->x, W[pos].y1);
len = min( cal_dis(false, W[pos].y1, itr->x), cal_dis(false, W[pos].y2, itr->x) );
if(len < D[itr->id].dist)
{
D[itr->id].dist = len;
D[itr->id].id = pos;
}
}
}
} } void fly_x() //假设现在bird都是沿着x轴方向飞行
{
vector<Object> T; //存储扫描时要处理的对象
for(int i = ; i <= N; i++)
{
T.push_back(Object(W[i].x1, W[i].y1, W[i].y2, i, WALL) );
if(W[i].x1 != W[i].x2) //必须要加末端,因为bird可能在延长线上
{
T.push_back(Object(W[i].x2, W[i].y1, W[i].y2, i, WALL) );
}
}
for(int i = ; i <= M; i++)
{
T.push_back(Object(B[i].x, B[i].y, , i, BIRD) );
}
sort(T.begin(), T.end());
scan(T, true);
reverse(T.begin(), T.end());
scan(T, true);
} void fly_y() //假设现在bird都是沿着y轴方向飞行
{
vector<Object> T; //存储扫描时要处理的对象
for(int i = ; i <= N; i++)
{
T.push_back(Object(W[i].y1, W[i].x1, W[i].x2, i, WALL) );
if(W[i].y1 != W[i].y2)
{
T.push_back(Object(W[i].y2, W[i].x1, W[i].x2, i, WALL) );
}
}
for(int i = ; i <= M; i++)
{
T.push_back(Object(B[i].y, B[i].x, , i, BIRD) ); //注意顺序
}
sort(T.begin(), T.end());
scan(T, false);
reverse(T.begin(), T.end());
scan(T, false);
} void discretization() //离散化处理
{
sort(cor_x.begin(), cor_x.end());
sort(cor_y.begin(), cor_y.end());
cor_x.erase(unique(cor_x.begin(), cor_x.end() ), cor_x.end() );
cor_y.erase(unique(cor_y.begin(), cor_y.end() ), cor_y.end() );
for(int i = ; i <= N; i++)
{
W[i].x1 = lower_bound(cor_x.begin(), cor_x.end(), W[i].x1) - cor_x.begin() + ;
W[i].x2 = lower_bound(cor_x.begin(), cor_x.end(), W[i].x2) - cor_x.begin() + ;
W[i].y1 = lower_bound(cor_y.begin(), cor_y.end(), W[i].y1) - cor_y.begin() + ;
W[i].y2 = lower_bound(cor_y.begin(), cor_y.end(), W[i].y2) - cor_y.begin() + ;
}
for(int i = ; i <= M; i++)
{
B[i].x = lower_bound(cor_x.begin(), cor_x.end(), B[i].x) - cor_x.begin() + ;
B[i].y = lower_bound(cor_y.begin(), cor_y.end(), B[i].y) - cor_y.begin() + ;
}
} int main()
{ //freopen("input.txt", "r", stdin);
scanf("%d %d", &N, &M);
for(int i = ; i <= N; i++)
{
scanf("%I64d %I64d %I64d %I64d", &W[i].x1, &W[i].y1, &W[i].x2, &W[i].y2);
if(W[i].x1 > W[i].x2) swap(W[i].x1, W[i].x2);
if(W[i].y1 > W[i].y2) swap(W[i].y1, W[i].y2);
cor_x.push_back(W[i].x1);
cor_x.push_back(W[i].x2);
cor_y.push_back(W[i].y1);
cor_y.push_back(W[i].y2);
}
for(int j = ; j <= M; j++)
{
scanf("%I64d %I64d", &B[j].x, &B[j].y);
cor_x.push_back(B[j].x);
cor_y.push_back(B[j].y);
}
discretization();
fly_x();
fly_y();
memset(ans, , sizeof(ans));
for(int i = ; i <= M; i++)
{
ans[ D[i].id ]++;
}
for(int i = ; i <= N; i++)
{
printf("%d\n", ans[i]);
}
return ;
}

POJ_3470 Walls 【离散化+扫描线+线段树】的更多相关文章

  1. hdu 4419 Colourful Rectangle (离散化扫描线线段树)

    Problem - 4419 题意不难,红绿蓝三种颜色覆盖在平面上,不同颜色的区域相交会产生新的颜色,求每一种颜色的面积大小. 比较明显,这题要从矩形面积并的方向出发.如果做过矩形面积并的题,用线段树 ...

  2. poj 1151 Atlantis (离散化 + 扫描线 + 线段树 矩形面积并)

    题目链接题意:给定n个矩形,求面积并,分别给矩形左上角的坐标和右上角的坐标. 分析: 映射到y轴,并且记录下每个的y坐标,并对y坐标进行离散. 然后按照x从左向右扫描. #include <io ...

  3. HDU 3265/POJ 3832 Posters(扫描线+线段树)(2009 Asia Ningbo Regional)

    Description Ted has a new house with a huge window. In this big summer, Ted decides to decorate the ...

  4. HDU 3642 - Get The Treasury - [加强版扫描线+线段树]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3642 Time Limit: 10000/5000 MS (Java/Others) Memory L ...

  5. 【BZOJ3958】[WF2011]Mummy Madness 二分+扫描线+线段树

    [BZOJ3958][WF2011]Mummy Madness Description 在2011年ACM-ICPC World Finals上的一次游览中,你碰到了一个埃及古墓. 不幸的是,你打开了 ...

  6. 【bzoj4491】我也不知道题目名字是什么 离线扫描线+线段树

    题目描述 给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串 输入 第一行n,表示A数组有多少元素接下来一行为n个整数A[i]接下来一个整数Q,表示询问数 ...

  7. POJ 1151 扫描线 线段树

    题意:给定平面直角坐标系中的N个矩形,求它们的面积并. 题解:建立一个四元组(x,y1,y2,k).(假设y1<y2)用来储存每一条线,将每一条线按x坐标排序.记录所有的y坐标以后排序离散化.离 ...

  8. hdu1542 Atlantis(扫描线+线段树+离散)矩形相交面积

    题目链接:点击打开链接 题目描写叙述:给定一些矩形,求这些矩形的总面积.假设有重叠.仅仅算一次 解题思路:扫描线+线段树+离散(代码从上往下扫描) 代码: #include<cstdio> ...

  9. P3722 [AH2017/HNOI2017]影魔(单调栈+扫描线+线段树)

    题面传送门 首先我们把这两个贡献翻译成人话: 区间 \([l,r]\) 产生 \(p_1\) 的贡献当且仅当 \(a_l,a_r\) 分别为区间 \([l,r]\) 的最大值和次大值. 区间 \([l ...

随机推荐

  1. gsm

    libosmocore Osmocom-BB wireshark 拦截一个短信内容

  2. Java 设计模式系列(十一)享元模式

    Java 设计模式系列(十一)享元模式 Flyweight 享元模式是对象的结构模式.享元模式以共享的方式高效地支持大量的细粒度对象. 一.享元模式的结构 享元模式采用一个共享来避免大量拥有相同内容对 ...

  3. fabric实现文本聚焦、可编辑

    var canvas = new fabric.Canvas('c'); var tex = new fabric.IText('click',{left:100,top:400});canvas.a ...

  4. [转]TCP的拥塞控制

    1.引言 计算机网络中的带宽.交换结点中的缓存和处理机等,都是网络的资源.在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就会变坏.这种情况就叫做拥塞. 拥塞控制就是防止 ...

  5. centos7安装kubernetes 1.1

    原文地址:http://foxhound.blog.51cto.com/1167932/1717105 前提:centos7 已经update yum update -y 一.创建yum源 maste ...

  6. java try catch finally return执行

    public static int testBasic(){ int i = 1; try{ i++; System.out.println("try block, i = "+i ...

  7. Java定时任务的实现

    本例依据Java自身提供的接口实现,通过监听器(Listener)和定时器(Timer)定时执行某个任务(Task).专业的开源工具可参考Quartz:http://www.opensymphony. ...

  8. windows过滤指定IP

    通过windows的安全管理策略工具我们可以实现对IP的过滤.整个过程比较复杂.我们以图形演示. 下面我们以windows 8.1作为示例. 1.控制面板=>管理工具=>本地安全策略. 2 ...

  9. 在Team Foundation Server (TFS)的代码库或配置库中查找文件或代码

    [update 2017.2.11] 最新版本的TFS 2017已经增加了代码搜索功能,可以参考这个链接 https://blogs.msdn.microsoft.com/visualstudioal ...

  10. Git 安装配置,key导入

    系统 Centos 6.5 安装git 命令  yum install  git 配置git用户名 git config --global user.name "yangchengguo&q ...