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. document.form.command.value

    问题:在一个JSP页面中需要多个提交按钮,每个按钮点击后需要把同一个form提交到不同的页面进行处理 解决:用JS. <html><head><title>一个表单 ...

  2. Android 创建Library Project(库项目)与引用操作

    由于在开发过程,为了实现未曾了解的某种效果与特定功能,而求助于网上优秀的开源项目,在使用过程中发现引用开源的Library Project(库项目),的确可以解决很多问题,而且也给出了一种思路,好的软 ...

  3. Beanstalkd使用

    Beanstalkd,一个高性能.轻量级的分布式内存队列系统,最初设计的目的是想通过后台异步执行耗时的任务来降低高容量Web应用系统的页面访问延迟,支持过有9.5 million用户的Facebook ...

  4. jackson - 生成jason工具-简单示例

    主页: http://jackson.codehaus.org/ https://github.com/FasterXML/jackson 当前jackson分为三部分,需要分别下载: jackson ...

  5. mybatis springmvc调用oracle存储过程,返回记录集

    参考: http://bbs.csdn.net/topics/390866155 辅助参考: http://www.2cto.com/kf/201307/226848.html http://blog ...

  6. Linux笔记(七) - 网络命令

    (1)给用户发信息:write例:write admin(ctrl+d结束)(2)发广播信息:wall例:wall hello world!(3)测试网络连通性:ping-c 发送次数例:ping - ...

  7. 开源第三方登录组件OAuthLogin2.0 支持QQ,阿里巴巴,淘宝,京东,蘑菇街,有赞等平台

    Nuget地址:https://www.nuget.org/packages/OAuthLogin2.0/ 项目结构说明: AuthorizationProviders文件夹下主要存放内置的授权平台. ...

  8. mac下为gdb创建证书赋权其调试其它应用

    1 使用/Applications/Utilities/Keychain Access.app创建证书 钥匙串访问->证书助理->创建证书 给证书随笔取一个名字,身份类型"自签名 ...

  9. Raft 实现日志复制同步

    Raft 实现日志复制同步 本篇文章以 John Ousterhout(斯坦福大学教授) 和 Diego Ongaro(斯坦福大学获得博士学位,Raft算法发明人) 在 Youtube 上的讲解视频及 ...

  10. 多线程——NSThread

    创建和启动线程 一个NSThread对象就代表一条线程 // 创建.启动线程 NSThread *thread = [[NSThread alloc] initWithTarget:self sele ...