【解题报告】pojP1436 Horizontally Visible Segments

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[8003][8003];
int n;  
  
struct
{  
    int l,r,n;  
} a[8003*5];  
  
struct node
{  
    int x,y1,y2;  
} s[8003];  
  
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=0;  
    if(l==r) return;  
    int k=(l+r)/2;  
    build(l,k,2*i);  
    build(k+1,r,2*i+1);  
}  
  
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!=-1)
    {  
        a[2*i].n=a[2*i+1].n=a[i].n;  
        a[i].n=-1;  
    }  
    if (l<=a[2*i].r)  
        add(l,r,2*i,m);  
    if (r>=a[2*i+1].l)  
        add(l,r,2*i+1,m);
}  
  
void push(int l,int r,int i,int m)  
{  
    if (a[i].n!=-1)  
    {  
        mark[a[i].n][m]=1;  
        return;  
    }  
    if ((a[i].l)==(a[i].r)) return;  
    if (a[i].n!=-1)  
    {  
        a[2*i].n=a[2*i+1].n=a[i].n;  
        a[i].n=-1;  
    }  
    if (l<=a[2*i].r) push(l,r,2*i,m);  
    if (r>=a[2*i+1].l) push(l,r,2*i+1,m);
}  
void show()
{
    int i,j,k;
    for(i=1;i<=n;i++)
    {
            for(j=1;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=1;i<=n;i++)  
        {  
            scanf("%d%d%d",&s[i].y1,&s[i].y2,&s[i].x);  
            s[i].y1*=2;  
            s[i].y2*=2; 
        }  
        sort(s+1,s+1+n,cmp);  
        memset(mark,false,sizeof(mark));  
        build(0,16000,1);  
        for(i = 1; i<=n; i++)  
        {  
            push(s[i].y1,s[i].y2,1,i);  
            add(s[i].y1,s[i].y2,1,i); 
            show();
            printf ("\n"); 
        }  
        ans=0;  
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)  
                if (mark[i][j]) for (k=1;k<=n;k++) if ((mark[i][k])&&(mark[j][k])) ans++;  
        printf("%d\n",ans);  
    }  
}  

 

posted @ 2017-03-11 19:49  Nitrate  阅读(199)  评论(0)    收藏  举报