// 12.8'06
// Hendrik Jan Hoogeboom leert programmeren

// high spies
// (1) inlezen
// (2) kortste pad vinden
// (3) maximaal pad mbv in-out formule

#include <iostream>
#include <string>  
#include <vector>

using namespace std;

// globaal (als 't maar werkt ..)

const int MAXnodes = 10000;

struct ListElt
{ int Naar, Heen, Weer;
} ;

// globale datastructuur
int 
  aantal_knopen,
  haven_van, haven_naar;
  vector<ListElt> AdjList[MAXnodes+1];
  vector<int> Path;


void leesin ()
{ int a,b,c,d, 
     i;
  ListElt tak;  
    
     cin >> aantal_knopen;
     for (i=1; i< aantal_knopen; i++)
     { 
       cin >> a >> b >> c >> d ;

       tak.Naar = b;
       tak.Heen = c;
       tak.Weer = d;
       AdjList[a].push_back( tak );
       tak.Naar = a;
       tak.Heen = d;
       tak.Weer = c;
       AdjList[b].push_back( tak );
       
     } // inst
       cin >> haven_van >> haven_naar;
} // leesin

bool search (int hier, int doel, int vorig)
{  // recursief zoeken in boom naar 'doel' 
   // recursiestack is dan de stapel ...
   // vanwege 'ongerichte' takken zorgen dat we niet terugwandelen
  vector<ListElt>::iterator loper;
  if (hier == doel) { return 1; }
  else
  {
  //  kinderen ...
    for ( loper = AdjList[hier].begin(); loper != AdjList[hier].end(); loper++)
    { 
      if ( loper->Naar != vorig )
       if ( search( loper->Naar, doel, hier ) )
       { Path.push_back(hier);
         return 1;
       }
    }
  }
  return 0;
}// search

int pushmax ()
{  vector<int>::iterator hier, vorig, volg;
   vector<ListElt>::iterator loper;
   int sigma_in, push;

   // oeps : het pad staat verkeerd om, niet dat de volgorde er toe doet ...
   // de eerste en laatste knoop op pad zijn eindpunten: overslaan
   hier = Path.end(); hier--;
   volg = hier; volg--;

   push = AdjList[*hier].begin()->Heen;
   // tja, lijkt te werken (gewicht uitgaande tak vertrekpunt)

   while (volg != Path.begin())
   {
     vorig = hier;
     hier = volg;
     volg--;

     // bereken sigma, de totale in- en uit-flux
     // die overigens gelijk aan elkaar moeten zijn
     sigma_in = 0;
     for ( loper = AdjList[*hier].begin(); loper != AdjList[*hier].end(); loper++) 
     {
        sigma_in += loper->Weer;
     }
     for ( loper = AdjList[*hier].begin(); loper != AdjList[*hier].end(); loper++)
     {  // gewicht naar volgende op pad is bovengrens:
        if (loper->Naar == *volg) 
        { if (push > loper->Heen) push = loper->Heen; continue; }
        // tak naar vorige negeren:
        if (loper->Naar == *vorig) continue;
        // overige knopen moeten genoeg 'ruimte' hebben
        // als we push van vorig via hier naar volg transporteren
        // geldt voor de resterende capaciteit van loper->Heen het gebruikelijke
        // sigma_uit - loper->Heen - push >=   loper->Weer 
        if (sigma_in - loper->Heen - loper->Weer < push )
           push = sigma_in - loper->Heen - loper->Weer ;
     }
     
   }
   return push;
} // pushmax


int pushmin ()
{  vector<int>::iterator hier, vorig, volg;
   vector<ListElt>::iterator loper;
   int sigma_in, push;
   int beschikbaar,
       vorig_in, vorig_uit, volg_in, volg_uit;

   // oeps : het pad staat verkeerd om, niet dat de volgorde er toe doet ...
   // de eerste en laatste knoop op pad zijn eindpunten: overslaan
   hier = Path.end(); hier--;
   volg = hier; volg--;
   
   push = AdjList[*hier].begin()->Heen;
   // tja, lijkt te werken (gewicht uitgaande tak vertrekpunt)
   
   while (volg != Path.begin())
   {
     vorig = hier;
     hier = volg;
     volg--;

     // bereken sigma, de totale in- (of uit-) flux
     sigma_in = 0;
     for ( loper = AdjList[*hier].begin(); loper != AdjList[*hier].end(); loper++) 
     {
        sigma_in += loper->Weer;
        if (loper->Naar == *volg)  
        { volg_in = loper->Weer;  volg_uit = loper->Heen; }
        if (loper->Naar == *vorig) 
        { vorig_in = loper->Weer; vorig_uit = loper->Heen; }
     }
     // gebruik alles, minus _uit naar vorig (mag niet) en volg (willen we niet)
     beschikbaar = sigma_in - vorig_uit - volg_uit;
     // misschien moet volg daar wat van gebruiken??
     if ( volg_in > vorig_uit ) beschikbaar -= (volg_in - vorig_uit);
     // dit gaan we gebruiken om containers om te leiden
     push -= beschikbaar;
     if ( push<=0 ) return 0;
   }
   return push;
} // pushmin

int main ()
{ // standaard vars 
 int Ninst, inst;
  // probleem vars
 int aantal;
 vector<int>::iterator blob;

     cin >> Ninst;
	 int t = 0;
	 for (int i = 1; i <= 300000000; i++)
		 t += i;
     for (inst=1; inst<=Ninst; inst++)
     { 
       leesin ();

       Path.push_back( haven_naar );
       search(  haven_van, haven_naar, 0 );
       cout << pushmin() << " " << pushmax() << endl;

       Path.clear() ;
       for (aantal=1; aantal <= aantal_knopen ; aantal++)
       { AdjList[aantal].clear(); }

     } // inst
} // main 
  
