POJ Horizontally Visible Segments
Horizontally Visible Segments
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 2318 | Accepted: 885 |
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
Source
题意:垂直线段的水平可见的条件为它们之间可以通过一条水平直线相连,且不经过任何一条垂直线段。如果有三条线段两两可见,那么它们是一个垂直线段的水平可见三角形。给定n条线段,问有多少这样的垂直线段的水平可见三角形。
首先 总坐标都得乘以2 ; 因为假设你有一线段[5,6] ,[3,5],[6,7],[5,6];如果不乘以2,第一条和第四条线段是不可见的,但事实是可见的。。。。自己想象下吧
思路:先按坐标x排好序,再依次查询和更新 ,我的更新和查询直接用一个函数带过,f[k].cover = -1 【f[k].left ,f[k].right】之间覆盖有不同的垂直线段,f[k].cover!=-1时,后面查询的线段覆盖前面的。。。line[i][j] = 1表示可见 。。。
最后一个三重循环就能得到答案了
View Code
1 #include<stdio.h> 2 #include<algorithm> 3 #include<string.h> 4 #include<iostream> 5 using namespace std; 6 struct SegmentLine{ 7 int x,y1,y2 ; 8 }s[8010] ; 9 bool line[8010][8010] ; 10 struct SegmentTree{ 11 int left,right,cover ; 12 int mid(){ return (left + right) >> 1 ;} 13 }f[80000] ; 14 bool cmp(SegmentLine a,SegmentLine b){ 15 return a.x < b.x ; 16 } 17 void build(int left,int right,int k){ 18 f[k].left = left ; 19 f[k].right = right ; 20 f[k].cover = 0; 21 if(left == right) return ; 22 int mid = f[k].mid() ; 23 build(left,mid,k<<1) ; 24 build(mid+1,right,k<<1|1) ; 25 } 26 void query(int left,int right,int idx,int k){ 27 if(left <= f[k].left && right >= f[k].right && f[k].cover != -1){ 28 line[f[k].cover][idx] = 1 ; 29 f[k].cover = idx ; 30 return ; 31 } 32 if(f[k].cover != -1){ 33 f[k<<1].cover = f[k<<1|1].cover = f[k].cover ; 34 f[k].cover = -1; 35 } 36 int mid = f[k].mid() ; 37 if(right <= mid) 38 query(left,right,idx,k<<1) ; 39 else if(left > mid) 40 query(left,right,idx,k<<1|1) ; 41 else { 42 query(left,mid,idx,k<<1) ; 43 query(mid+1,right,idx,k<<1|1) ; 44 } 45 } 46 int main(){ 47 int T ; 48 scanf("%d",&T) ; 49 while(T--){ 50 int n; 51 scanf("%d",&n) ; 52 build(0,16000,1) ; 53 memset(line,0,sizeof(line)) ; 54 for(int i=1;i<=n;i++){ 55 scanf("%d%d%d",&s[i].y1,&s[i].y2,&s[i].x) ; 56 s[i].y1 *= 2 ; 57 s[i].y2 *= 2 ; 58 } 59 sort(&s[1],&s[1]+n,cmp) ; 60 for(int i=1;i<=n;i++){ 61 query(s[i].y1,s[i].y2,i,1) ; 62 } 63 int ans = 0 ; 64 for(int i=1;i<n;i++){ 65 for(int j=i+1;j<=n;j++){ 66 if(line[i][j]) 67 for(int k=j+1;k<=n;k++) 68 if(line[j][k] && line[i][k]) 69 ans++ ; 70 } 71 } 72 printf("%d\n",ans) ; 73 } 74 return 0; 75 }