题目大意:
1.给出n条垂直x轴的线段。
2.定义两条线段水平可见当且仅当存在一条平行于x轴的线段,它的两个端点落在这两条线段上并且不与第三条线段相交。
3.定义三条线段构成一个三角形当且仅当这三条线短两两之间水平可见。
求这n条线段可以构成多少个三角形。
//====================================================================
思路:
非常自然的想法就是求出所有n条线段之间水平可见的关系然后用SPFA之类的做法求长度为3的环的个数。
求线段之间水平可见关系可以利用线段树做:按x坐标排序,覆盖的y1-y2之间所有的点。如果查询和覆盖同时进行,覆盖的判断和平时不太相同:当前区间被完全包含的时候不能直接覆盖就返回,而是要先往下找了以后返回了再覆盖。
这里有个很妙的trick,对于以下数据:
1 4 1
1 2 2
3 4 3
1 4 4
以上的做法会判断第一条和第四条不水平可见。但只要
在覆盖的时候把y1和y2乘以2就能解决这个问题了(但是空间花费必然变大了)。
对于判断三元环的算法?直接暴力吧。。
想象每一个线段是一个抽象的点,两条线段水平可见则根据定义连一条不与第三条线段相交的线段。这样构图以后会发现这是一个平面图。而平面图有一个性质:
边数<=(点数-2)*3
可以这么想:已经存在一个平面图了,并且这个平面图中边数已经达到最大,此时再加入一个点,如果这个点可以和四个以上包括四个的点相连并且满足平面图的性质。那么之前的那个平面图的边数就不是最大化的,因为这四个以上的点之间肯定还能再连一条以上的边。所以每加入一个点边数增加3,初始的时候三个点三条边构成三角形。
这样说不是很严密,但是应该是没有错的吧。。求指教。
嗯,这题还学习了容器vector,之前用得极少,而且这种东西不用马上就丢了。以后每次新学的东西都要整理起来、
vector:阿德
Code:
#include
#include
#include
#include
#include
#include
using namespace std;
struct Line
{
} l[8010];
vector v[8010];
int a[70000];
int s, t, z, n;
int cmp(Line g, Line h)
{
}
void cover(int be, int en, int now)
{
}
int main()
{
//==================================================
//==================================================
//
printf("%d:%d %d %d\n", i, l[i].x, l[i].y1, l[i].y2);
//
for (iter = v[i].begin(); iter != v[i].end(); iter++)
//
printf("%d ", *iter);
//
printf("\n");
}