【37%】【poj1436】Horizontally Visible Segments
| Time Limit: 5000MS | Memory Limit: 65536K | |
| Total Submissions: 5200 | Accepted: 1903 |
Description
segments are said to form a triangle of segments if each two of them are horizontally visible. How many triangles can be found in a given set of vertical segments?
Task
Write a program which for each data set:
reads the description of a set of vertical segments,
computes the number of triangles in this set,
writes the result.
Input
The first line of each data set contains exactly one integer n, 1 <= n <= 8 000, equal to the number of vertical line segments.
Each of the following n lines consists of exactly 3 nonnegative integers separated by single spaces:
yi', yi'', xi - y-coordinate of the beginning of a segment, y-coordinate of its end and its x-coordinate, respectively. The coordinates satisfy 0 <= yi' < yi'' <= 8 000, 0 <= xi <= 8 000. The segments are disjoint.
Output
Sample Input
1
5
0 4 4
0 3 1
3 4 2
0 2 2
0 2 3
Sample Output
1
Source
【题解】
这题的意思是在一个平面里面给你n条线段,是竖直的,然后给你它的横坐标x和竖直方向上的两个端点坐标y1,y2;
然后“可见”的意思是,在这个平面里面放一段水平线段。然后问是否有两条输入的竖直线段被这条水平线段经过。如果有的话还需要这条水平线在这两条线段中间没有穿过其他的输入的竖直线。如果满足上述条件。则称这两条线段可见。只要有任意一条水平线(最少一条)满足就称它们为可见的。
题目说的triangle的意思就是说要找到3条这样两两可见的线段。
问这样的triangle有多少个。
思路:
先按照x轴升序排序那些输入的竖直线段。我这里在排序前记录了它原来的编号。但是我觉得完全可以在排序完之后再记录它们的编号。因为最后只要求数目不要求输出方案;
然后就把这个问题看做是平面上的线段,即从右往左在竖直面上不断地覆盖线段。
覆盖一条线段x的时候,就看一下,当前的竖直面上有哪些之前线段会被覆盖到。如果被覆盖到那说明什么???当然就是它们俩是可见的!
所以我们用一个bo[MAXN][MAXN]来记录某两个编号的线段是否可见。
在做线段树的时候顺便记录就可以了。
然后就是最后的统计数目;
这样
for (int i = 1;i <= n;i++)
for (int j = i+1;j <= n;j++)
if (bo[i][j])
for (int k = i+1;k <= j-1;k++)
if (bo[i][k] && bo[k][j])
ans++;
很容易理解的吧
最后还要提一个问题。
就是类似这样的数据
1 4 0
1 2 1
3 4 1
1 4 2
就是当我们前3个都覆盖了,第4个再覆盖上去编号为4的和编号为1的是否是可见的呢??
显然应该是可见的才对。
因为y坐标的2到3是没有被编号2和编号3线段覆盖的。
但是如果我们正常地按线段树去做会得出1和4是不可见的错解,所以需要把y坐标的对应值都乘上2;
2 8 0
2 4 1
6 8 1
2 8 2
这样线段树就能够判断出[4,6]这个区间是编号1的了。然后4和1就会被判断为可见了。
【代码】
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> const int MAXN = 8000+10; using namespace std; struct bian //记录线段的信息。
{
int x, y1, y2,bianhao;
}; bian a[MAXN];
int n,color[MAXN*2*4];//color相当于线段树中的lazy_tag现在被用来记录线段的颜色
__int64 ans;//记录答案
bool bo[MAXN][MAXN];//判断任意两条线段是否可见。 void input_data()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d%d%d", &a[i].y1, &a[i].y2, &a[i].x);
a[i].y1 = a[i].y1*2;a[i].y2 = a[i].y2*2;//为防止错节要乘2
if (a[i].y1 > a[i].y2)
{
int t = a[i].y1;
a[i].y1 = a[i].y2;
a[i].y2 = t;
}
a[i].bianhao = i;
}
} int cmp(const bian &a, const bian &b)
{
if (a.x < b.x)
return 1;
return 0;
} void deal_withlazy(int rt)//处理懒惰标记
{
if (color[rt] != 0)
{
color[rt << 1] = color[rt << 1 | 1] = color[rt];//直接往下传递就可以了。
color[rt] = 0;
}
} void query(int l, int r, int now, int begin, int end, int rt)
{//当前节点的编号为rt,它的区间范围是begin,end;
if (color[rt] != 0)//因为l,r肯定是和begin和end有交集的
{//如果begin和end全部被覆盖成了某种颜色
bo[now][color[rt]] = true;//则这种颜色肯定要被覆盖最少一部分了 则记录它们可见。
bo[color[rt]][now] = true;
return;
}
if (begin >= end)
return;
deal_withlazy(rt);//这句可以省略掉
int m = (begin + end) >> 1;
if (l <= m)
query(l, r, now, begin,m,rt<<1);
if (m < r)
query(l, r, now, m+1,end,rt<<1|1);
} void updata(int l, int r, int now, int begin, int end, int rt)
{
if (l <= begin && end <= r) //如果完全在需要覆盖的里面就直接覆盖颜色
{
color[rt] = now;
return;
}
int m = (begin + end) >> 1;
if (begin >= end)
return;
deal_withlazy(rt);//这句就不能省了,因为要对下面进行操作了。
if (l <= m)
updata(l, r, now, begin,m,rt<<1);
if (m < r)
updata(l, r, now, m+1,end,rt<<1|1);
} void get_ans()
{
for (int i = 1; i <= n; i++)
{
query(a[i].y1, a[i].y2, a[i].bianhao, 0, 16000,1);
updata(a[i].y1, a[i].y2, a[i].bianhao, 0, 16000, 1);
}
for (int i = 1; i <= n - 1; i++)
for (int j = i + 1; j <= n; j++)//求解
if (bo[i][j])
for (int k = i + 1; k <= j - 1; k++)
if (bo[k][i] && bo[k][j])
ans++;
} void init() //每次的初始化。
{
memset(bo, false, sizeof(bo));
memset(color, 0, sizeof(color));
ans = 0;
} void output_ans()
{
cout << ans << endl;
} int main()
{
//freopen("F:\\rush.txt", "r", stdin);
//freopen("F:\\rush_out.txt", "w", stdout);
int t;
scanf("%d", &t);
while (t--)
{
init();
input_data();
sort(a + 1, a + 1 + n, cmp);
get_ans();
output_ans();
}
return 0;
}
【37%】【poj1436】Horizontally Visible Segments的更多相关文章
- POJ 1436 Horizontally Visible Segments (线段树·区间染色)
题意 在坐标系中有n条平行于y轴的线段 当一条线段与还有一条线段之间能够连一条平行与x轴的线不与其他线段相交 就视为它们是可见的 问有多少组三条线段两两相互可见 先把全部线段存下来 并按x ...
- POJ 1436 Horizontally Visible Segments(线段树)
POJ 1436 Horizontally Visible Segments 题目链接 线段树处理染色问题,把线段排序.从左往右扫描处理出每一个线段能看到的右边的线段,然后利用bitset维护枚举两个 ...
- poj 1436 && zoj 1391 Horizontally Visible Segments (Segment Tree)
ZOJ :: Problems :: Show Problem 1436 -- Horizontally Visible Segments 用线段树记录表面能被看见的线段的编号,然后覆盖的时候同时把能 ...
- (中等) POJ 1436 Horizontally Visible Segments , 线段树+区间更新。
Description There is a number of disjoint vertical line segments in the plane. We say that two segme ...
- 【解题报告】pojP1436 Horizontally Visible Segments
http://poj.org/problem?id=1436 题目大意:有n条平行于x轴的线段,每条线段有y坐标,如果两条线段有一段x坐标数值相等,且中间没有其它线段阻隔,则称这两条线段"照 ...
- poj1436 Horizontally Visible Segments
这是一个区间更新的题目,先将区间放大两倍,至于为什么要放大可以这样解释,按照从左到右有4个区间,y值是[1,5],[1,2],[3,4],[1,4]如果不放大的话,查询[1,4]区间和前面区间的”可见 ...
- POJ 1436 Horizontally Visible Segments
题意: 有一些平行于y轴的线段 ,两条线段称为互相可见当且仅当存在一条水平线段连接这两条 与其他线段没交点. 最后问有多少组 3条线段,他们两两是可见的. 思路: 线段树,找出两两可见的那些组合, ...
- POJ 1436 (线段树 区间染色) Horizontally Visible Segments
这道题做了快两天了.首先就是按照这些竖直线段的横坐标进行从左到右排序. 将线段的端点投影到y轴上,线段树所维护的信息就是y轴区间内被哪条线段所覆盖. 对于一条线段来说,先查询和它能相连的所有线段,并加 ...
- POJ 1436.Horizontally Visible Segments-线段树(区间更新、端点放大2倍)
水博客,水一水. Horizontally Visible Segments Time Limit: 5000MS Memory Limit: 65536K Total Submissions: ...
随机推荐
- 编码与乱码(05)---GBK与UTF-8之间的转换--转载
原文地址:http://www.blogjava.net/pengpenglin/archive/2010/02/22/313669.html [GBK转UTF-8] 在很多论坛.网上经常有网友问“ ...
- nuxt配置sass
没有比这更简单的了 只需要安装 node-sass sass-loader 就可以了 npm i node-sass sass-loader -D 然后就可以直接使用了: <style lang ...
- 为什么要学习Numerical Analysis
前几日我发了一个帖子,预告自己要研究一下 Numerical Analysis 非常多人问我为啥,我统一回答为AI-----人工智能 我在和教授聊天的时候,忽然到了语言发展上 我说:老S啊(和我关系 ...
- CSS伪元素与伪类的区别
伪类和伪元素介绍 伪类:伪类选择元素基于的是当前元素处于的状态,或者说元素当前所具有的特性,而不是元素的id.class.属性等静态的标志.由于状态是动态变化的,所以一个元素达到一个特定状态时,它可能 ...
- JS学习笔记 - fgm练习 - 输入法下拉框 三元表达式
<script> window.onload = function() { var oBtn = document.getElementsByTagName('input')[0]; va ...
- 快速创建SSH信任实现无密码登录
1. 生成本机的公私钥匙对[oracle@Oracle11_2 scripts]$ -t rsa Generating public/private rsa key pair. Enter file ...
- 1、移动端 2、后台 3、 移动端,Web 端 4、 PC端
移动端: 1.公众号:停开心 住总物业 2.app: iso Android 停开心,住总停开心 后台:停开心智慧停车管理平台(所有的停车场) 移动端,Web端: 海投OA,公司OA PC端:收费软 ...
- Spring Boot + Jersey
Jersey是一个很好的Java REST API库.当你用Jersey实现REST的时候.是很自然的.同一时候Spring Boot是Java世界中还有一个很好的工具.它降低了程序的应用配置(< ...
- 【BZOJ 4556】字符串
[链接]h在这里写链接 [题意] 给你一个长度为n(n<=10^5)的字符串以及一个整数m(m<=10^5),代表询问的次数. 每个询问由4个整数a,b,c,d给出 ...
- 关于idea新建子目录时往父目录名字后叠加而不是树形结构的解决方法(转)
我们在IDEA中创建子目录时,子目录总是在父目录后面叠加而不是树形,如下 我们可以打开项目窗口的右上角的设置标志, 将红圈选项的√先去掉,创建好子目录后再将它选中就可以