Advanced Data Structures :: Segment Tree
Description
平面上有几条线段,这些线段都是平行于 y 轴的。
如果存在一条平行于 x 轴的直线能够与两条线段相交,
并且直线在两个交点之间的部分,没有与其他线段相交。
则称这两条线段相互“可视”。
三条线段可以成为一个组合,如果组合内的三条线段两两“可视”,
则该组线段形成了一个特殊的三角形。
告诉你平面上所有线段的x、y1、y2 坐标(线段为 (x, y1) 到 (x, y2) ),
问有多少个这样的三角形组合。
题目保证没有线段相交于同一点。
Type
Advanced Data Structures :: Segment Tree
Analysis
我们将所有线段画在纸上,然后逆时针旋转90度来看。
这题有点像铺地毯(或者说贴海报)似的,一层覆盖一层。
由此,可以想到利用线段树来求解。
把所有线段按 x 坐标排序,然后按顺序添加到线段树中。
而一条线段“可视”的线段中所有 x 坐标比它小的线段,正好是被它覆盖到的线段(不一定完全覆盖)。
至于 x 坐标比它大的,因为“可视”是相互的,后面的线段肯定可以发现这组“可视”的关系。
这样,我们就可以在查询线段树的时候,用一个 vector 数组来存储某条线“可视”的 x 坐标比它小的线段。
然后好像也没有什么比较好的算法,就只好暴力求解(复杂度O(n^4))有多少组特殊的三角形了。
其中有几点要注意的:
// POJ 1436 // Horizontally Visible Segments // by A Code Rabbit #include <algorithm> #include <cstdio> #include <cstring> #include <vector> using namespace std; #define LSon(x) ((x) << 1) #define RSon(x) ((x) << 1 | 1) const int MAXN = 8002; const int ROOT = 1; struct Seg { int w; }; struct SegTree { Seg node[MAXN * 2 << 2]; void Build() { memset(node, -1, sizeof(node)); } void Push(int pos) { if (node[pos].w != -1) { node[LSon(pos)].w = node[RSon(pos)].w = node[pos].w; node[pos].w = -1; } } void Modify(int l, int r, int pos, int x, int y, int z) { if (x <= l && r <= y) { node[pos].w = z; return; } Push(pos); int m = l + r >> 1; if (x <= m) Modify(l, m, LSon(pos), x, y, z); if (y > m) Modify(m + 1, r, RSon(pos), x, y, z); } void Query(int l, int r, int pos, int x, int y, int z, vector<int>* vec, bool* bo) { if (node[pos].w != -1) { if (!bo[node[pos].w]) { vec[z].push_back(node[pos].w); bo[node[pos].w] = true; } return; } if (l == r) return; int m = l + r >> 1; if (x <= m) Query(l, m, LSon(pos), x, y, z, vec, bo); if (y > m) Query(m + 1, r, RSon(pos), x, y, z, vec, bo); } }; struct Segment { int y1, y2; int x0; }; int n; Segment seg[MAXN]; vector<int> vec[MAXN]; bool bo[MAXN]; SegTree tree; int Cmp(Segment a, Segment b) { return a.x0 < b.x0; } int main() { int tot_case; scanf("%d", &tot_case); while (tot_case--) { // Input. scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d%d%d", &seg[i].y1, &seg[i].y2, &seg[i].x0); seg[i].y1 *= 2; seg[i].y2 *= 2; } // Solve. sort(seg, seg + n, Cmp); for (int i = 0; i < n; i++) vec[i].clear(); tree.Build(); for (int i = 0; i < n; i++) { memset(bo, false, sizeof(bo)); tree.Query(0, 8000 * 2, ROOT, seg[i].y1, seg[i].y2, i, vec, bo); tree.Modify(0, 8000 * 2, ROOT, seg[i].y1, seg[i].y2, i); } int ans = 0; for (int i = 0; i < n; i++) { int num_seg1= i; for (int j = 0; j < vec[num_seg1].size(); j++) { int num_seg2 = vec[num_seg1][j]; for (int k = 0; k < vec[num_seg2].size(); k++) for (int l = 0; l < vec[num_seg1].size(); l++) if (vec[num_seg1][l] == vec[num_seg2][k]) ans++; } } // Output. printf("%d\n", ans); } return 0; }