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行 y1,y2,x表示线段的y坐标和x坐标,问水平方向上3元组两两可见的组数。
这题。。。简直无语了,狂TLE了一晚上,害得我不断优化,今天早上去掉了我写的那个“输入挂”,秒A了。(数据后面没'\n',我的挂写错了,判'\n'结束)。
思路:按x坐标排序编号,从左往右,依次加入线段,加入之前,先统计它下面的可见线段(我是将此次线段push_back到下面的线段集合中,每次都是 小编号.push_back(大编号)且判重),然后update此线段的y坐标范围为此线段编号。
最后暴力查找。
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#include <set>;
using namespace std;
typedef long long LL;
#define maxn 8010
int r[maxn],y1[maxn],y2[maxn],x[maxn];
int next[maxn];
vector<int>g[maxn];
int mak[maxn<<3];
int cmp(int a, int b)
{
return x[a]<x[b];
}
bool found(int i,int x, int l, int r)
{
int m;
while(l<r)
{
m=(l+r)>>1;
if(g[i][m]==x) return true;
if(g[i][m]>x) r=m-1;
else l=m+1;
}
return g[i][l]==x;
}
void pushdown(int rt)
{
if(mak[rt])
{
mak[rt<<1]=mak[rt<<1|1]=mak[rt];
mak[rt]=0;
}
}
void update(int L, int R, int p, int l, int r, int rt)
{
if(L<=l && R>=r)
{
mak[rt]=p;
return;
}
pushdown(rt);
int m=(l+r)>>1;
if(L<=m)update(L,R,p,l,m,rt<<1);
if(R>m)update(L,R,p,m+1,r,rt<<1|1);
if(mak[rt<<1]&&mak[rt<<1]==mak[rt<<1|1])mak[rt]=mak[rt<<1];
}
void query(int L, int R, int p, int l, int r, int rt)
{
if(mak[rt])
{
if(next[mak[rt]]==p)return;
next[mak[rt]]=p;
g[mak[rt]].push_back(p);
return;
}
if(l==r)return;
pushdown(rt);
int m=(l+r)>>1;
if(L<=m)query(L,R,p,l,m,rt<<1);
if(R>m) query(L,R,p,m+1,r,rt<<1|1);
}
int main()
{
int i,j,k,m,n;
int T;
scanf("%d",&T);
while(T--)
{
int N=-1;
scanf("%d",&n);
memset(mak,0,sizeof(mak));
memset(next,0,sizeof(next));
for(i=1;i<=n;i++)
{
scanf("%d %d %d",y1+i,y2+i,x+i);
y1[i]=y1[i]<<1|1,y2[i]=y2[i]<<1|1;
if(N<y2[i])N=y2[i];
r[i]=i;
g[i].clear();
}
sort(r+1,r+1+n,cmp);
for(i=1;i<=n;i++)
j=r[i],
query( y1[j],y2[j],i,1,N,1),
update(y1[j],y2[j],i,1,N,1);
int ans=0;
int has[maxn];
for(i=1;i<=n;i++)
{
int s=g[i].size();
for(j=0;j<s;j++)
{
int a=g[i][j];
int ss=g[a].size();
for(k=0;k<ss;k++)
if(found(i,g[a][k],0,s-1))
ans++;
}
}
printf("%d\n",ans);
}
}