Horizontally Visible Segments POJ - 1436(线段树区间覆盖)

There is a number of disjoint vertical line segments in the plane. We say that two segments are horizontally visible if they can be connected by a horizontal line segment that does not have any common points with other vertical segments. Three different vertical 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 the input contains exactly one positive integer d equal to the number of data sets, 1 <= d <= 20. The data sets follow.

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
The output should consist of exactly d lines, one line for each data set. Line i should contain exactly one integer equal to the number of triangles in the i-th data set.
Sample Input
1
5
0 4 4
0 3 1
3 4 2
0 2 2
0 2 3
Sample Output
1

题意:
n条竖直线段,如果有水平线不经过其他直线,则称为可见。3条直线互相可见成为”三角形“。求多少“三角形”
思路:
线段树区间覆盖的思路很好写,但关键是后面3个for的枚举,如果达到n3方复杂度,对于n≤8000来说是不可接受的。
但是一共8000个点,y最大也是8000.
对于第一个线段,要使得被其他所有线段”看到“,得满足剩下的点依次被填充。

那么假设第二个线段填充了len长度,那么第二个线段最多只能被len个线段看到,第一个线段被看到的个数减少len。

由此易得最多只有8000k(k是一个较小的常数)对可以互相看见。

那么复杂度实际为n2logn, 对于(1,2),(3,4),(2,3),(2,3)作为闭区间可能会被掩盖,所以每个点乘以2,点区间扩展为段区间。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 8000 * 2 + 2;
bool maze[maxn / 2][maxn / 2];//开成int类型会mle

struct Node
{
    int l,r;
    int cover;
}t[maxn << 2];

struct Point
{
    int x,y1,y2;
}p[maxn / 2];

int cmp(Point a,Point b)
{
    return a.x < b.x;
}

void pushup(int i)
{
    if(t[i * 2].cover == -1 || t[i * 2 + 1].cover == -1)t[i].cover = -1;
    else if(t[i * 2].cover != t[i * 2 + 1].cover)t[i].cover = -1;
    else t[i].cover = t[i * 2].cover;
}

void pushdown(int i)
{
    if(t[i].cover != -1)
    {
        t[i * 2].cover = t[i * 2 + 1].cover = t[i].cover;
    }
}

void build(int i,int l,int r)
{
    t[i].l = l;t[i].r = r;
    t[i].cover = 0;
    if(l == r)return;
    int m = (l + r) >> 1;
    build(i * 2,l,m);
    build(i * 2 + 1, m + 1,r);
    pushup(i);
}

void update(int i,int x,int y,int v)
{
    if(x <= t[i].l && t[i].r <= y)
    {
        t[i].cover = v;
        return;
    }
    pushdown(i);
    int m = (t[i].l + t[i].r) >> 1;
    if(x <= m)update(i * 2,x,y,v);
    if(y > m)update(i * 2 + 1,x,y,v);
    pushup(i);
}

void query(int i,int x,int y,int v)
{
    if(t[i].cover != -1)
    {
        maze[t[i].cover][v] = maze[v][t[i].cover] = 1;
        return;
    }
    int m = (t[i].l + t[i].r) >> 1;
    if(x <= m)query(i * 2,x,y,v);
    if(y > m)query(i * 2 + 1,x,y,v);
}

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n;scanf("%d",&n);
        for(int i = 1;i <= n;i++)
        {
            scanf("%d%d%d",&p[i].y1,&p[i].y2,&p[i].x);
            p[i].y1 *= 2;p[i].y2 *= 2;
        }
        sort(p + 1,p + 1 + n,cmp);
        memset(maze,0,sizeof(maze));
        build(1,0,maxn);
        for(int i = 1;i <= n;i++)
        {
            query(1,p[i].y1,p[i].y2,i);
            update(1,p[i].y1,p[i].y2,i);
        }
        
        int ans = 0;
        for(int i = 1;i <= n;i++)
        {
            for(int j = i + 1;j <= n;j++)
            {
                if(maze[i][j])
                {
                    for(int k = j + 1;k <= n;k++)
                    {
                        if(maze[i][k] && maze[j][k])
                        {
                            ans++;
                        }
                    }
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

发布了628 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/104076276