Horizontally Visible Segments(线段树 + 区间更新)

Horizontally Visible Segments
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 3805   Accepted: 1392

Description

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

 

      题意:

      给出 T,代表有 T 组样例。每个样例给出一个 n(1 ~ 8000),代表有 n 条垂直的线,后给出这 n 条垂直线的 y1,y2,x (0 ~ 8000)值,寻找任意的三条线,两两之间用横线穿过当且仅当穿过这两条垂直线,寻找有多少个组合满足这样条件的三条线。

 

      思路:

      线段树 + 区间覆盖。不需要离散化,但是存在一个问题就是,有可能两条线用一条水平线穿过只穿过了两条线的端点,而线段树维护子节点是维护一个线段元的覆盖情况的,所以要对 y 坐标方法处理,即 X 2。这样的话就可以转化成线段元来处理了。每添加一条线前先查询该区间能到达的线分别是哪些,再插入进去,用 Map 标记每条线的到达情况,后暴力求解 Map [ i ] [ j ] == 1 且 Map [ i ] [ k ] 且 Map [ j ] [ k ] 的一共有多少即可。记得建树和查询的时候也要对树 X 2 来建和查询,不够细心 WA 了几次。数据比较小,也不需要离散化。

 

       AC: 

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

using namespace std;

const int MAX = 8005;

typedef struct {
        int x, y1, y2;
} node;

node line[MAX];
bool Map[MAX][MAX];
int cover[MAX * 5];
int n;

bool cmp (node a, node b) {
        return a.x < b.x;
}


void push_down (int node) {
        if (cover[node]) {
                cover[node << 1] = cover[node];
                cover[node << 1 | 1] = cover[node];
                cover[node] = 0;
        }
}

void build (int node, int l, int r) {
        if (r == l) {
                cover[node] = 0;
        } else {
                int mid = (r + l) >> 1;
                build(node << 1, l, mid);
                build(node << 1 | 1, mid + 1, r);
                cover[node] = 0;
        }
}

void updata (int node, int l, int r, int cl, int cr, int c) {
        if (cl > r || cr < l) return;
        if (cl <= l && cr >= r) {
                cover[node] = c;
                return;
        }
        if (r == l) return;

        push_down(node);
        int mid = (r + l) >> 1;
        if (cl <= mid) updata(node << 1, l, mid, cl, cr, c);
        if (cr >= mid) updata(node << 1 | 1, mid + 1, r, cl, cr, c);
}

void query (int node, int l, int r, int ql, int qr, int q) {
        if (ql > r || qr < l) return;
        if (ql <= l && qr >= r) {
                if (cover[node])  {
                        Map[q][ cover[node] ] = 1;
                        return;
                }
        }
        if (r == l) return;

        push_down(node);
        int mid = (r + l) >> 1;
        if (ql <= mid) query(node << 1, l, mid, ql, qr, q);
        if (qr >= mid) query(node << 1 | 1, mid + 1, r, ql, qr, q);
}

void solve () {

        int sum = 0;
        for (int i = n; i >= 3; --i) {
                for (int j = i - 1; j >= 2; --j) {
                        if (Map[i][j]) {
                                for (int k = j - 1; k >= 1; --k) {
                                        if (Map[i][k] && Map[j][k]) ++sum;
                                }
                        }
                }
        }

        printf("%d\n", sum);
}

int main() {
        int t;
        scanf("%d", &t);

        while (t--) {

                scanf("%d", &n);

                memset(Map, 0, sizeof(Map));
                build(1, 0, MAX * 2);

                for (int i = 1; i <= n; ++i) {
                        scanf("%d%d%d", &line[i].y1, &line[i].y2, &line[i].x);
                }

                sort(line + 1, line + 1 + n, cmp);

                for (int i = 1; i <= n; ++i) {
                        query(1, 0, MAX * 2, line[i].y1 * 2, line[i].y2 * 2, i);
                        updata(1, 0, MAX * 2, line[i].y1 * 2, line[i].y2 * 2, i);
                }

                solve();
        }

        return 0;
}

 

你可能感兴趣的:(visible)