一、题面

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. Web01 基础

    网址组成(四部分) 协议  http,https (https是加密的http) 主机  g.cn zhihu.com之类的网址 端口 HTTP协议默认80,因此一般不用填写 路径 下面的 / 和 / ...

  2. 10 Consensus and Profile

    Problem A matrix is a rectangular table of values divided into rows and columns. An m×nm×n matrix ha ...

  3. web端跨域调用webapi(转)

    在做Web开发中,常常会遇到跨域的问题,到目前为止,已经有非常多的跨域解决方案. 通过自己的研究以及在网上看了一些大神的博客,写了一个Demo 首先新建一个webapi的程序,如下图所示: 由于微软已 ...

  4. UVa 11136 Hoax or what (STL)

    题意:有 n 天,每天有m个数,开始的前一天没有数据,然后每天从这个里面拿出一个最大的和最小的,求 n 天的最大的和最小的差值相加. 析:一看就知道用set啊,多简单的STL,不过要注意,开long ...

  5. 第二周leetcode

    4/4 这周莫名得忙,一天是做编译,一天是做模式识别作业,(一天刷魔兽皮肤),周末玩了两天,总的来说还是松懈了,大概只做了两天的leetcode,刷了10道题,羞愧羞愧. 决定每次把代码附上在这个总结 ...

  6. plsql导入导出表数据

    导出表结构: Tools(工具)-->Export User Objects(导出用户对象) -->选择要导出的表(包括Sequence等)-->.sql文件,导出的都为sql文件 ...

  7. persona 典型用户

    1.姓名:王涛 2.年龄:22 3.收入:基本无收入 4.代表用户在市场上的比例和重要性:王涛为铁道学生.本软件的用户主要是学生和老师,尤其是广大的铁大学子,所以此典型用户的重要性不言而喻,而且比例相 ...

  8. task3:词频统计

    相关的类: java.util.regex.Pattern static Pattern compile(String regex) //编译模式 static Pattern compile(Str ...

  9. append2 给append 添加回调方法

    $.fn.append2 = function(html, callback) { var originalHtmlLength = $("body").html().length ...

  10. freemarker获取变量的范围的问题

    今天做freemarker的时候,想用一下全局的变量.就是在a.ftl 和 b.ftl页面里面,使用a.action里面放入request的变量.a.action的视图页面是a.ftl ,b.ftl是 ...