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;
}

 

### 实现水平翻转图像或元素的方法 在编程中,要实现图像或元素的水平翻转,通常可以通过多种方式完成。以下是几种常见的方法: #### 方法一:通过矩阵操作实现图像水平翻转 对于二维数组表示的图像数据结构,可以交换每一行中的像素位置来实现水平翻转。具体来说,就是将每行的第一个像素与最后一个像素互换,第二个像素与倒数第二个像素互换,依此类推。 ```python def horizontal_flip(image_matrix): flipped_image = [] for row in image_matrix: flipped_row = row[::-1] # 使用切片反转列表 flipped_image.append(flipped_row) return flipped_image ``` 这种方法适用于简单的灰度图或者 RGB 图像,其中 `image_matrix` 是一个嵌套列表,代表图像的像素值[^3]。 --- #### 方法二:利用图形库函数 许多现代图形处理库提供了内置的功能用于快速执行图像变换操作。例如,在 Python 的 PIL (Pillow) 库中,可以直接调用 `.transpose()` 函数并指定参数为 `Image.FLIP_LEFT_RIGHT` 来实现水平翻转。 ```python from PIL import Image # 打开图片文件 img = Image.open('example.jpg') # 水平翻转 flipped_img = img.transpose(Image.FLIP_LEFT_RIGHT) # 保存结果 flipped_img.save('flipped_example.jpg') ``` 此方法简单高效,适合需要频繁进行复杂图像编辑的应用场景[^4]。 --- #### 方法三:CSS 中的水平翻转效果 如果目标是在网页前端展示时动态调整 DOM 元素的方向,则可借助 CSS 属性 `-webkit-transform`, `transform` 完成这一需求。设置其值为 `scaleX(-1)` 即能轻松达成目的。 ```css .flipped-element { transform: scaleX(-1); /* 或者 -ms-transform, -moz-transform */ } ``` 上述样式规则会使得应用该类名的所有 HTML 节点沿 X 轴方向镜像显示[^5]。 --- #### 注意事项 当涉及硬件层面的具体细节时需要注意某些平台特定的行为差异。比如旧版本 X Window System 下曾经存在黑白色彩常量定义 (`BlackPixel()`, `WhitePixel()`) ,但在较新的标准里已经被移除,因此不应再硬编码这些数值[^2] 。同样地,任何依赖固定分辨率单位的设计也应考虑跨设备兼容性问题——就像控件尺寸扩展仅按单个像素递增那样可能不够灵活[^1] 。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值