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
题意:
n条竖直线段,如果有水平线不经过其他直线,则称为可见。3条直线互相可见成为”三角形“。求多少“三角形”
思路:
线段树区间覆盖的思路很好写,但关键是后面3个for的枚举,如果达到n3方复杂度,对于n≤8000来说是不可接受的。
但是一共8000个点,y最大也是8000.
对于第一个线段,要使得被其他所有线段”看到“,得满足剩下的点依次被填充。
那么假设第二个线段填充了len长度,那么第二个线段最多只能被len个线段看到,第一个线段被看到的个数减少len。
由此易得最多只有8000k(k是一个较小的常数)对可以互相看见。
那么复杂度实际为n2logn, 对于(1,2),(3,4),(2,3),(2,3)作为闭区间可能会被掩盖,所以每个点乘以2,点区间扩展为段区间。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 8000 * 2 + 2;
bool maze[maxn / 2][maxn / 2];//开成int类型会mle
struct Node
{
int l,r;
int cover;
}t[maxn << 2];
struct Point
{
int x,y1,y2;
}p[maxn / 2];
int cmp(Point a,Point b)
{
return a.x < b.x;
}
void pushup(int i)
{
if(t[i * 2].cover == -1 || t[i * 2 + 1].cover == -1)t[i].cover = -1;
else if(t[i * 2].cover != t[i * 2 + 1].cover)t[i].cover = -1;
else t[i].cover = t[i * 2].cover;
}
void pushdown(int i)
{
if(t[i].cover != -1)
{
t[i * 2].cover = t[i * 2 + 1].cover = t[i].cover;
}
}
void build(int i,int l,int r)
{
t[i].l = l;t[i].r = r;
t[i].cover = 0;
if(l == r)return;
int m = (l + r) >> 1;
build(i * 2,l,m);
build(i * 2 + 1, m + 1,r);
pushup(i);
}
void update(int i,int x,int y,int v)
{
if(x <= t[i].l && t[i].r <= y)
{
t[i].cover = v;
return;
}
pushdown(i);
int m = (t[i].l + t[i].r) >> 1;
if(x <= m)update(i * 2,x,y,v);
if(y > m)update(i * 2 + 1,x,y,v);
pushup(i);
}
void query(int i,int x,int y,int v)
{
if(t[i].cover != -1)
{
maze[t[i].cover][v] = maze[v][t[i].cover] = 1;
return;
}
int m = (t[i].l + t[i].r) >> 1;
if(x <= m)query(i * 2,x,y,v);
if(y > m)query(i * 2 + 1,x,y,v);
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
int n;scanf("%d",&n);
for(int i = 1;i <= n;i++)
{
scanf("%d%d%d",&p[i].y1,&p[i].y2,&p[i].x);
p[i].y1 *= 2;p[i].y2 *= 2;
}
sort(p + 1,p + 1 + n,cmp);
memset(maze,0,sizeof(maze));
build(1,0,maxn);
for(int i = 1;i <= n;i++)
{
query(1,p[i].y1,p[i].y2,i);
update(1,p[i].y1,p[i].y2,i);
}
int ans = 0;
for(int i = 1;i <= n;i++)
{
for(int j = i + 1;j <= n;j++)
{
if(maze[i][j])
{
for(int k = j + 1;k <= n;k++)
{
if(maze[i][k] && maze[j][k])
{
ans++;
}
}
}
}
}
printf("%d\n",ans);
}
return 0;
}