http://poj.org/problem?id=1436

题目大意:有n条平行于x轴的线段,每条线段有y坐标,如果两条线段有一段x坐标数值相等,且中间没有其它线段阻隔,则称这两条线段”照面“。如果三条线段两两互能照面,则称这三条线段为一组。问这n条线段中有多少组?

可以看到题目中n<=8000,于是开始想n log n的算法,但是当我看那题的discuss时,有人说

这题数据太无语了……O(n^2lgn) TLE , O(n^3)的算法266ms……

O(n^3)能过?于是想到如果能判断并保存两两线段之间的是否照面关系,然后n*n*n暴力搜索互相照面的三条线段。。。

现在问题只剩下如何判断并保存两两线段之间的是否照面关系了,这就是典型的线段树区间覆盖问题

1、先把所有线段按x坐标排一下序

2、线段树a[i].l表示左边界,a[i].r表示右边界,a[i].n表示占据该区域的线段号码,建树

3、压过程:把线段从树顶压下去,若碰到延迟标记就顺便压下子树,若碰到a[i].n!=0的子树,mark[a[i].n][x(目前压的线段号)]=1

4、冲过程:把线段加入线段树,找到属于该线段的区间(顺路推下延迟标记),若发现该区间a[i].n!=0,直接覆盖掉!因为线段已经被排过序,所以从宏观上看,就是x坐标大的线段把x坐标小的线段挡住了,以后的线段也不会再在该区间与x坐标小的线段照面了(想的时候在这里卡了很长时间)

5、回到第三步,直到所有线段都经过了冲压过程

6、O(n^3)暴力搜索互相照面的三条线段

我的程序:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
bool mark[][];
int n; struct
{
int l,r,n;
} a[*]; struct node
{
int x,y1,y2;
} s[]; int cmp(node a,node b)
{
return a.x<b.x;
} void build(int l,int r,int i)
{
a[i].l=l;
a[i].r=r;
a[i].n=;
if(l==r) return;
int k=(l+r)/;
build(l,k,*i);
build(k+,r,*i+);
} void add(int l,int r,int i,int m)
{
if ((l<=a[i].l)&&(a[i].r<=r))
{
a[i].n=m;
return;
}
if (a[i].n!=-)
{
a[*i].n=a[*i+].n=a[i].n;
a[i].n=-;
}
if (l<=a[*i].r)
add(l,r,*i,m);
if (r>=a[*i+].l)
add(l,r,*i+,m);
} void push(int l,int r,int i,int m)
{
if (a[i].n!=-)
{
mark[a[i].n][m]=;
return;
}
if ((a[i].l)==(a[i].r)) return;
if (a[i].n!=-)
{
a[*i].n=a[*i+].n=a[i].n;
a[i].n=-;
}
if (l<=a[*i].r) push(l,r,*i,m);
if (r>=a[*i+].l) push(l,r,*i+,m);
}
void show()
{
int i,j,k;
for(i=;i<=n;i++)
{
for(j=;j<=n;j++)
printf ("%d ",mark[i][j]);
printf ("\n");
}
}
int main()
{
int t,ans,i,x,y1,y2,j,k;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=;i<=n;i++)
{
scanf("%d%d%d",&s[i].y1,&s[i].y2,&s[i].x);
s[i].y1*=;
s[i].y2*=;
}
sort(s+,s++n,cmp);
memset(mark,false,sizeof(mark));
build(,,);
for(i = ; i<=n; i++)
{
push(s[i].y1,s[i].y2,,i);
add(s[i].y1,s[i].y2,,i);
show();
printf ("\n");
}
ans=;
for(i=;i<=n;i++)
for(j=;j<=n;j++)
if (mark[i][j]) for (k=;k<=n;k++) if ((mark[i][k])&&(mark[j][k])) ans++;
printf("%d\n",ans);
}
}

【解题报告】pojP1436 Horizontally Visible Segments的更多相关文章

  1. POJ 1436 Horizontally Visible Segments (线段树&#183;区间染色)

    题意   在坐标系中有n条平行于y轴的线段  当一条线段与还有一条线段之间能够连一条平行与x轴的线不与其他线段相交  就视为它们是可见的  问有多少组三条线段两两相互可见 先把全部线段存下来  并按x ...

  2. POJ 1436 Horizontally Visible Segments(线段树)

    POJ 1436 Horizontally Visible Segments 题目链接 线段树处理染色问题,把线段排序.从左往右扫描处理出每一个线段能看到的右边的线段,然后利用bitset维护枚举两个 ...

  3. poj 1436 && zoj 1391 Horizontally Visible Segments (Segment Tree)

    ZOJ :: Problems :: Show Problem 1436 -- Horizontally Visible Segments 用线段树记录表面能被看见的线段的编号,然后覆盖的时候同时把能 ...

  4. (中等) POJ 1436 Horizontally Visible Segments , 线段树+区间更新。

    Description There is a number of disjoint vertical line segments in the plane. We say that two segme ...

  5. 【37%】【poj1436】Horizontally Visible Segments

    Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5200   Accepted: 1903 Description There ...

  6. POJ 1436 Horizontally Visible Segments

    题意: 有一些平行于y轴的线段 ,两条线段称为互相可见当且仅当存在一条水平线段连接这两条  与其他线段没交点. 最后问有多少组  3条线段,他们两两是可见的. 思路: 线段树,找出两两可见的那些组合, ...

  7. POJ 1436 (线段树 区间染色) Horizontally Visible Segments

    这道题做了快两天了.首先就是按照这些竖直线段的横坐标进行从左到右排序. 将线段的端点投影到y轴上,线段树所维护的信息就是y轴区间内被哪条线段所覆盖. 对于一条线段来说,先查询和它能相连的所有线段,并加 ...

  8. poj1436 Horizontally Visible Segments

    这是一个区间更新的题目,先将区间放大两倍,至于为什么要放大可以这样解释,按照从左到右有4个区间,y值是[1,5],[1,2],[3,4],[1,4]如果不放大的话,查询[1,4]区间和前面区间的”可见 ...

  9. POJ 1436.Horizontally Visible Segments-线段树(区间更新、端点放大2倍)

    水博客,水一水. Horizontally Visible Segments Time Limit: 5000MS   Memory Limit: 65536K Total Submissions:  ...

随机推荐

  1. jquery换肤

    <script src="script/jquery-2.1.0.js"></script>      <link href="style/ ...

  2. STL内存管理

    1. 概述 STL Allocator是STL的内存管理器,也是最低调的部分之一,你可能使用了3年stl,但却不知其为何物. STL标准如下介绍Allocator the STL includes s ...

  3. Hadoop学习笔记-008-CentOS_6.5_64_yum安装mysql

    ******************************卸载mysql***************************** 第一步,查看centos上是否已经安装了mysql数据库 # rp ...

  4. linq左连接查询加上into后怎么查询右表是否为空

    //判断右表是否为空并为映射表进行赋值标志var query=from q in product join m in favProduct on q.Name equals m.Name into t ...

  5. Linux驱动技术(四) _异步通知技术

    异步通知的全称是"信号驱动的异步IO",通过"信号"的方式,放期望获取的资源可用时,驱动会主动通知指定的应用程序,和应用层的"信号"相对应, ...

  6. C++源码的调用图生成

    前言 之前受知乎用户mailto1587启发,写了个C++源码的调用图生成器,可以以图示法显示C++函数的调用关系, 代码放在了github仓库里,仅供参考: CodeSnippet/python/S ...

  7. pom.xml配置详解

    <!--可以免费转载,转载时请注明出处  http://pengqb.iteye.com .--><project xmlns="http://maven.apache.o ...

  8. Arduino入门学习

    一直听到许多做物联网.智能家居的控制器使用的是Arduino,从师兄那里拿到了一块Arduino开发板,进行了一下午的学习,感觉这个适合小孩子们玩:) 废话少说,总结一下,便于以后可能会用得到.我主要 ...

  9. java多线程安全问题 静态函数的修饰

    /* 如果同步函数被静态修饰后,使用的锁是什么呢? 通过验证,发现不在是this.因为静态方法中也不可以定义this. 静态进内存是,内存中没有本类对象,但是一定有该类对应的字节码文件对象. 类名.c ...

  10. liunx下search文件内容的几种方式

    第一种.使用vim来search内容 /regex_word,从上到下匹配 ?regex_word,从下到上匹配 n是获取下一个匹配字符串,N是获取上一个匹配字符串. 第二种.使用grep命令 gre ...