poj1436 Horizontally Visible Segments
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.
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.
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条垂直于x轴的线段的数据y1,y2,x,求出有几个三条线段一组的三元组并且他们兩兩能相见的。
思路:对y轴建树,将x排序,然后按顺序边询问边擦入,用mark[i][j]表示i往左可以看到j。最后用一个三重循环计算答案。
但是注意:0,4,1 和 0,2,2 和 3,4,2这三条线段覆盖的结果是区间0~4通过线段树查找可见线段是两条,其实是3条(2~3可见另一条)
这里可以将y轴×2表示。这样就能解决这样的问题
1 /* 2 * Author: Joshua 3 * Created Time: 2014年07月19日 星期六 15时26分20秒 4 * File Name: poj1436.cpp 5 */ 6 #include<cstdio> 7 #include<cstring> 8 #include<algorithm> 9 using namespace std; 10 11 #define maxn 8008 12 #define L(x) (x <<1) 13 #define R(x) (x << 1 |1) 14 15 int T,maxv; 16 bool mark[maxn][maxn]; 17 struct node 18 { 19 int l,r,color; 20 } e[maxn << 4]; 21 struct edge 22 { 23 int y1,y2,x; 24 edge(int Y1=0,int Y2=0,int X=0):y1(Y1),y2(Y2),x(X){} 25 bool operator < (const edge &a) const 26 { 27 return x<a.x; 28 } 29 } s[maxn]; 30 void build(int x,int l,int r) 31 { 32 e[x].color=0; 33 e[x].l=l; 34 e[x].r=r; 35 if (l==r) return; 36 int mid = l+r >>1; 37 build(L(x),l,mid); 38 build(R(x),mid+1,r); 39 } 40 void query(int x,int l,int r,int v) 41 { 42 if (e[x].color) 43 { 44 mark[v][e[x].color]=true; 45 return; 46 } 47 int left=e[x].l,right=e[x].r; 48 if (left==right) return; 49 int mid = left+right >>1; 50 if (l<=mid) query(L(x),l,r,v); 51 if (r>mid) query(R(x),l,r,v); 52 } 53 54 void pushDown(int x) 55 { 56 if (e[x].color) 57 { 58 e[L(x)].color=e[R(x)].color=e[x].color; 59 e[x].color=0; 60 } 61 } 62 63 void updata(int x,int l,int r,int v) 64 { 65 int left=e[x].l,right=e[x].r; 66 if (l<=left && right<=r) 67 { 68 e[x].color=v; 69 return; 70 } 71 pushDown(x); 72 int mid=left +right >>1; 73 if (l<=mid) updata(L(x),l,r,v); 74 if (r>mid) updata(R(x),l,r,v); 75 } 76 77 void solve() 78 { 79 int n,x,y1,y2; 80 scanf("%d",&n); 81 maxv=0; 82 for (int i=1;i<=n;++i) 83 { 84 scanf("%d%d%d",&y1,&y2,&x); 85 y1 <<=1; 86 y2 <<=1; 87 s[i]=edge(y1,y2,x); 88 if (y2>maxv) maxv=y2; 89 } 90 build(1,0,maxv); 91 sort(s+1,s+n+1); 92 memset(mark,0,sizeof(mark)); 93 for (int i=1;i<=n;++i) 94 { 95 query(1,s[i].y1,s[i].y2,i); 96 updata(1,s[i].y1,s[i].y2,i); 97 } 98 int ans=0; 99 for (int i=1;i<=n;++i) 100 for (int j=i+1;j<=n;++j) 101 if (mark[j][i]) 102 for (int k=1;k<=i;++k) 103 if (mark[i][k] && mark[j][k]) 104 ++ans; 105 printf("%d\n",ans); 106 } 107 108 int main() 109 { 110 scanf("%d",&T); 111 while (T) 112 { 113 solve(); 114 --T; 115 } 116 117 return 0; 118 }