poj 1436 Horizontally Visible Segments

题目大意:

在一个平面内,有一些竖直的线段,若两条竖直线段之间可以连一条水平线,这条水平线不与其他竖直线段相交,称这两条竖直线段为相互可见的。若存在三条竖直线段,两两“相互可见”,则构成“线段三角形”。给出一些竖直的线段,问一共有多少“线段三角形”。

 

首先处理端点问题:想象一下若同一x位置有两条线段,y坐标为1~23~4。其实中间的空当2~3之间是可以引水平线段的,而这里我们都用整数处理,那条水平线段就被忽略了,可能会导致有一些水平相互可见的线段在计算中被忽略了,这里我们扩大y坐标之间的空间,这时我们就可以多出一个整数来便于我们的整数处理,这样就可以简单地处理端点问题,并且它对于所有情况都有很好的效果.自己画个图就明白了

 

线段处理:首先对线段以X大小进行排序;再进行询问,询问时是以当前的线段与先前的线段是不是相互可见的;再进行更新。

这里我们用到了覆盖的原则。如果不明白先做做这个题吧。http://poj.org/problem?id=2777

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
class Node
{
public:
int l ,r ,c;
};
class segment
{
public:
int y1,y2,x;
};
Node tree[40024];
int v[10024];
segment seg[10024];
vector<int>see[10024];
class Tree
{
public:
void Maketree( int l, int r ,int cnt );
void Update( int l, int r ,int cnt, int id );
void Query( int l ,int r, int cnt, int id );
};
void Tree::Maketree( int l ,int r, int cnt )
{
tree[cnt].l = l;
tree[cnt].r = r;
tree[cnt].c = -1;//-1表示该区间有个线段;
if( l == r ) return ;
int mid = ( l + r )>>1;
Maketree( l , mid , cnt*2 );
Maketree( mid + 1 ,r ,cnt*2+1 );
}
void Tree::Update( int l ,int r, int cnt , int id )
{
if( l <= tree[cnt].l&& r >= tree[cnt].r )//符合要求的区间被覆盖
{
tree[cnt].c = id;
return;
}
else
{
if( tree[cnt].c != -1 )//如果不为-1则表示该区间(y轴这个区间)只有一条线段那么就要复原
{
tree[cnt*2].c = tree[cnt*2+1].c = tree[cnt].c;
tree[cnt].c = -1;
}
int mid = ( tree[cnt].l + tree[cnt].r )>>1;
if( r > mid )
Update( l , r , cnt*2 +1 , id );
if( l <= mid )
Update( l , r , cnt*2 , id );
if( tree[cnt*2].c == tree[cnt*2+1].c )//由下往上更新
tree[cnt].c = tree[cnt*2].c;
else tree[cnt].c = -1;
}
}
void Tree::Query(int l, int r ,int cnt , int id)
{
// if( l > tree[cnt].r || r > tree[cnt].l )
// return ;
if( tree[cnt].c != -1 )
{
if( v[tree[cnt].c] != id )
{
see[ tree[cnt].c ].push_back( id );
v[tree[cnt].c] = id;
}
return ;
}
// Query( l , r, cnt*2 + 1, id );
// Query( l , r , cnt *2 ,id );
if( tree[cnt].l == tree[cnt].r ) return;
else
{
int mid = ( tree[cnt].l + tree[cnt].r )>>1;
if( mid < l )
Query( l , r, cnt*2 + 1, id );
else
{
if( r <= mid )
Query( l , r, cnt*2 , id );
else
{
Query( l , mid , cnt *2 ,id );
Query( mid + 1 , r ,cnt*2+1 , id );
}
}
}
}
bool cmp( segment a ,segment b )
{
return a.x < b.x;
}
int main( )
{
int n,m;
while( scanf( "%d",&n )==1 )
{
while( n-- )
{
Tree e;
scanf( "%d",&m );
for( int i=0; i<m ;i++ )
{
scanf( "%d%d%d",&seg[i].y1, &seg[i].y2 ,&seg[i].x );
seg[i].y1 *= 2;
seg[i].y2 *= 2;
see[i].clear();
}
e.Maketree( 0 , 16000 , 1 );
sort( seg , seg+m ,cmp );
memset( v , -1 ,sizeof( v ) );
for( int i = 0 ; i< m ;i++ )
{
e.Query( seg[i].y1, seg[i].y2 , 1 , i );
e.Update( seg[i].y1 , seg[i]. y2 , 1 ,i );
}
int ans = 0;
for( int i= 0 ; i < m ;i++ )
{
int t = see[i].size();
for( int j= 0 ; j< t ;j++ )
{
for( int k = j+1 ;k< t ;k++ )
{
int z = see[see[i][j]].size();
for( int l = 0 ; l < z ; l++ )
{
if( see[i][k] == see[see[i][j]][l] )
{
ans++;
break;
}
}
}
}
}
printf( "%d\n",ans );
}
}
return 0;
}


你可能感兴趣的:(visible)