/*
    题意:一个人在起点(x0,y0)处开始向下滑雪,给出n段门(一段一段向下),人必须穿过每一段,
    不能越过去,问最后到达终点的最小滑行距离

    有个结论:最优的滑行路线是由一些线段组成的。而且这些线段的端点必定是起点或者门的两个端点,
    并有可能有一条垂直于X轴的线段(最后一段,从某个点直接滑到最后一个门)。

    然后对每一段的两个端点,求其到终点的最小距离dp[i][side]
    转移是枚举下一个直达的端点(是直达,不用绕弯)
    dp[i,side] = min( dp[i,side] , dp[j,s] + dist() )
    往下枚举时更新左端点,右端点!!

    启示:题目规模知道应该是O(n^2)算法,最优性猜想dp
           直线走最近,枚举可以直达的端点!!
*/

#include
<cstdio>
#include
<cstring>
#include
<algorithm>
#include
<cmath>

using namespace std;

const double EPS = 1e-10;
const double DINF = 1e300;
const int MAXN = 1010;

struct Point
{
    
double x,y;
    Point()
{}
    Point(
double _x,double _y)
    
{
        x 
= _x;
        y 
= _y;
    }

}
;

Point seg[MAXN][
2];
double dp[MAXN][2];

int sign(double x)
{
    
return x<-EPS?-1:x>EPS;
}


Point intersert(Point 
&A, Point &B, double y)
{
    
double dx = A.x-B.x;
    
double dy = A.y-B.y;    
    
return Point(A.x+(y-A.y)*dx/dy, y);
}

double dist(Point &A,Point &B)
{
    
double x = A.x-B.x;
    
double y =A.y-B.y;
    
return sqrt(x*x+y*y);
}


bool leftTurn(Point &O,Point &A,Point &B)//B is in the left of OA
{
    
double x1 = (A.x-O.x), y1 = (A.y-O.y);
    
double x2 = (B.x-O.x), y2 = (B.y-O.y);
    
return  sign( x1*y2 - x2*y1 ) > 0 ;
}


bool noRightTurn(Point &O,Point &A,Point &B)//B is in the left of ,or on OA
{
    
double x1 = (A.x-O.x), y1 = (A.y-O.y);
    
double x2 = (B.x-O.x), y2 = (B.y-O.y);
    
return  sign( x1*y2 - x2*y1 ) >= 0 ;
}


int main()
{
#ifdef ONLINE_JUDGE
#else
    freopen(
"in","r",stdin);
#endif

    
int n;
    
while(scanf("%d",&n),n)
    
{
        scanf(
"%lf%lf",&seg[0][0].x,&seg[0][0].y);
        
for(int i=1;i<=n;i++)
        
{
            scanf(
"%lf%lf%lf",&seg[i][0].y,&seg[i][0].x,&seg[i][1].x);
            seg[i][
1].y = seg[i][0].y;
        }

        dp[n][
0= dp[n][1= 0.0;
        
forint i = n-1 ,j; i >= 0 ; i-- )
            
forint side = 0 ; side < 2 ; side++ )
            
{
                dp[i][side] 
= DINF;
                Point next[
2= { seg[i+1][0] , seg[i+1][1] };
                Point pt 
= seg[i][side];
                
for( j = i+1 ; j<=n ; j++ )
                
{
                    
//不能直达时要跳出
                    if( leftTurn( pt, seg[j][1], next[0]) || leftTurn( pt, next[1], seg[j][0]))break;
                    
//往下枚举时要更新左端点和右端点!!
                    if( noRightTurn( pt, next[0], seg[j][0]))
                    
{
                        next[
0= seg[j][0];
                        dp[i][side] 
= min(dp[i][side],dist(pt,next[0])+dp[j][0]);
                    }

                    
if( noRightTurn( pt, seg[j][1], next[1]))
                    
{
                        next[
1= seg[j][1];
                        dp[i][side] 
= min(dp[i][side],dist(pt,next[1])+dp[j][1]);
                    }

                }

                
if( j > n )//directly to finish line
                {
                    
double y = seg[n][0].y;
                    next[
0= intersert(pt,next[0],y);
                    next[
1= intersert(pt,next[1],y);
                    
//由于直达终点线,可以不用到端点处
                    if(pt.x < next[0].x )dp[i][side] = min(dp[i][side], dist(pt,next[0]));
                    
else if(pt.x > next[1].x)dp[i][side] = min(dp[i][side], dist(pt,next[1])); 
                    
else dp[i][side] = min(dp[i][side], pt.y-y);//直下
                }

                
if( i == 0 )break;
            }

            printf(
"%.10f\n",dp[0][0]);
    }

    
return 0;
}