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条线段,问在这n条线段中,最多能组成多少个相互可见的三角形,所谓相互可见,就是用一条直线连接这条线段和那条线段的顶点(这里的线段是垂直于x轴的),那么这道题怎么做呢?
【解题思路】刚看懂这个题的题意,马上想到了一个相似的问题,贴海报,那么解决这道题的最优策略是怎样的呢?当然是对输入的一堆线段按照高度排序之后,做成线段树就好了,线段树需要增加一个标记记录覆盖当前区间的线段编号,这里为col。做成线段树之后,由于这里有区间更新,要考虑Push_Down,接下来就是手动推一下样例,但是怎么推怎么不对(-><-),看了一下别人的blog,发现了一个新问题,例如0,4,1 和 0,2,2 和 3,4,2。这个数据就能说明问题了,如果不乘以2 那么 第二条 和 第三条就把 x=2 这一段堵死了,其实还有2-3这一个线段的。解决了这个问题,本题就完美解决了。实现细节见我的AC代码。
【AC代码】
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int nn = 8005;
bool vis[nn][nn];
struct seg{
int l,r,h;
friend bool operator<(const seg &a,const seg &b)
{
return a.h<b.h;
}
}seg[nn];
struct node{
int l,r,col;
}Tree[nn<<3];
void Push_Down(int rt)
{
if(Tree[rt].col!=-1)
{
Tree[rt<<1].col=Tree[rt<<1|1].col=Tree[rt].col;
Tree[rt].col=-1;
}
}
void Build(int l,int r,int rt)
{
Tree[rt].l=l,Tree[rt].r=r,Tree[rt].col=-1;
if(l==r)return ;
int m = (l+r)>>1;
Build(lson);
Build(rson);
}
void Update(int L,int R,int val,int rt)
{
if(L<=Tree[rt].l&&Tree[rt].r<=R)
{
Tree[rt].col = val;
return ;
}
Push_Down(rt);
int m = (Tree[rt].l+Tree[rt].r)>>1;
if(L<=m) Update(L,R,val,rt<<1);
if(m<R) Update(L,R,val,rt<<1|1);
}
void query_ans(int L,int R,int val,int rt)//询问和当前线段可以相互可见的线段
{
if(Tree[rt].col!=-1)
{
vis[Tree[rt].col][val] = true;
return ;
}
if(Tree[rt].l==Tree[rt].r)return ;
int m =(Tree[rt].l+Tree[rt].r)>>1;
if(L<=m) query_ans(L,R,val,rt<<1);
if(m<R) query_ans(L,R,val,rt<<1|1);
}
int main()
{
ios::sync_with_stdio();cin.tie(0);
int T,n;
scanf("%d",&T);
while(T--)
{
cin>>n;
for(int i=1; i<=n; i++)
{
scanf("%d%d%d",&seg[i].l,&seg[i].r,&seg[i].h);
seg[i].l<<=1,seg[i].r<<=1;
}
sort(seg+1,seg+n+1);
Build(1,nn*2,1);
memset(vis,0,sizeof(vis));
for(int i=1; i<=n; i++)
{
query_ans(seg[i].l,seg[i].r,i,1);
Update(seg[i].l,seg[i].r,i,1);
}
int ans = 0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(vis[i][j])
{
for(int k=1; k<=n; k++)
{
if(vis[i][k]&&vis[j][k]) ans++;
}
}
}
}
printf("%d\n",ans);
}
return 0;
}