一、题面

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. Java程序设计——对象序列化

    对象序列化的目标是将对象保存到磁盘中或允许在网络中直接传输对象,对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久保存在磁盘上,通过网络将这种二进制流传输到另 ...

  2. 20155311 2016-2017-2 《Java程序设计》第8周学习总结

    20155311 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 通用API: •日志API • 日志: 日志对信息安全意义重大,审计.取证.入侵检测等都会用 ...

  3. BurpSuite安装和配置

    Burp Suite是什么 Burp Suite 是用于攻击web 应用程序的集成平台.它包含了许多Burp工具,这些不同的burp工具通过协同工作,有效的分享信息,支持以某种工具中的信息为基础供另一 ...

  4. Google’s Project Tango is shutting down because ARCore is already here

    https://www.theverge.com/2017/12/15/16782556/project-tango-google-shutting-down-arcore-augmented-rea ...

  5. MySQL性能调优与架构设计——第1章 MySQL 基本介绍

    第1章 MySQL 基本介绍 前言:作为最为流行的开源数据库软件之一, MySQL 数据库软件已经是广为人知了. 但是为了照顾对MySQL还不熟悉的读者,这章我们将对 MySQL 做一个简单的介绍.主 ...

  6. [翻译] FastReport Class Hierarchy (FastReport 组件类层次结构)

    "TfrxComponent" is the base class for all FastReport components. Objects of this type have ...

  7. Unity3d中使用Lua

    对于手机游戏,如果可以在线更新以实现bug修复.新功能添加等等,其好处自不必多说. 通过C#的反射机制,也可以实现某种程度上的脚本级更新,具体可以参考 http://docs.unity3d.com/ ...

  8. c++中的隐藏及重载、重写与隐藏的区别

    c/c++中的隐藏  举个栗子 class A { public : void fun1(int a, int b) { cout<<"abcd"<<end ...

  9. 配置sql server 允许远程连接

    如果要想远程连接数据库那么则需要在一个局域网中或一个路由器中才可以做到 接下来就是具体的操作检查sqlserver数据库是否允许远程连接 具体操作为 (1)打开数据库,用本地帐户登录,右击第一个选项, ...

  10. jdk动态代理 案例

    import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflec ...