#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<set>
#include<cmath>
#include<map>
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define inf (1<<29)
#define MAX_V 10000
using namespace std;
typedef pair<int,int> ii;
typedef pair<ii,char> iic;
typedef pair<ii,ii> ii2;

// library start
struct edge
{
  int to,cap,cost,rev;
  edge(int to=-inf,int cap=-inf,int cost=-inf,int rev=-inf):to(to),cap(cap),cost(cost),rev(rev){}
};
int V;
vector<edge> G[MAX_V];
int h[MAX_V];
int dist[MAX_V];
int prevv[MAX_V],preve[MAX_V];

void add_edge(int from,int to,int cap,int cost)
{
  G[from].push_back(edge(to,cap,cost,G[to].size()));
  G[to].push_back(edge(from,0,-cost,G[from].size()-1));
}

int min_cost_flow(int s,int t,int f)
{
  int res = 0;
  rep(i,MAX_V)h[i] = 0;
  while(f > 0)
    {
      priority_queue<ii,vector<ii>,greater<ii> > Q;
      rep(i,MAX_V)dist[i] = inf;
      dist[s] = 0;
      Q.push(ii(0,s));
      while(!Q.empty())
	{
	  ii p = Q.top(); Q.pop();
	  int v = p.second;
	  if(dist[v] < p.first)continue;
	  rep(i,G[v].size())
	    {
	      edge &e = G[v][i];
	      if(e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to])
		{
		  dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
		  prevv[e.to] = v;
		  preve[e.to] = i;
		  Q.push(ii(dist[e.to],e.to));
		}
	    }
	}

      //cout << "dist[" << t << "] = " << dist[t] << endl;
      //if(dist[t] == inf)return -1;
      if(dist[t] == inf)break;
      rep(v,MAX_V)h[v] += dist[v];

      int d = f;
      for(int v=t; v!=s; v=prevv[v])
	{
	  d = min(d,G[prevv[v]][preve[v]].cap);
	}
      f -= d;
      //cout << "d = "<< d << endl;
      res += d*h[t];
      for(int v=t;v!=s;v=prevv[v])
	{
	  edge &e = G[prevv[v]][preve[v]];
	  e.cap -= d;
	  G[v][e.rev].cap += d;
	}
    }
  return res;
}

// library end

int n,g,index,last,last2;
map<iic,int> table;//table[ii(ノード番号,時刻)] = index

int getIndex(int node,int tm,char c)
{
  if(table.find(iic(ii(node,tm),c)) != table.end())return table[iic(ii(node,tm),c)];
  table[iic(ii(node,tm),c)] = index++,++V;
  return index-1;
}

void init()
{
  rep(i,MAX_V)G[i].clear();
  V = 0;
  index = 0;
  table.clear();
}

int main()
{
  while(cin >> n,n)
    {
      init();
      table[iic(ii(0,0),'0')] = index++,++V;
      last = MAX_V-3;
      last2 = last+1;

      vector<ii2> input;
      vector<int> cost;
      set<int> station[n+1][2];// 0->到着、1->出発

      REP(i,1,n)
	{
	  int m;
	  cin >> m;
	  rep(_,m)
	    {
	      int x,y,c;
	      cin >> x >> y >> c;
	      cost.push_back(c);
	      input.push_back(ii2(ii(i,x),ii(i+1,y)));
	      station[i][1].insert(x);
	      station[i+1][0].insert(y);
	      station[i+1][1].insert(y);
	    }
	}

      REP(i,1,n+1)
	{
	  for(set<int>::iterator it=station[i][0].begin();it!=station[i][0].end();it++)
	    {
	      getIndex(i,*it,'0');
	      //cout << "到着 node = " << i << " time = " << *it << " is " << getIndex(i,*it,0) << endl;
	    }
	  for(set<int>::iterator it=station[i][1].begin();it!=station[i][1].end();it++)
	    {
	      getIndex(i,*it,'1');
	      //cout << "出発 node = " << i << " time = " << *it << " is " << getIndex(i,*it,1) << endl;
	    }
	}

      rep(i,input.size())
	{
	  ii from,to;
	  from = input[i].first;
	  to = input[i].second;
	  add_edge(getIndex(from.first,from.second,'1'),getIndex(to.first,to.second,'0'),1,cost[i]);
	}

      REP(i,2,n+1)
	{
	  for(set<int>::iterator it2 = station[i][0].begin(); it2 != station[i][0].end();it2++)
	    {
	      int id = getIndex(i,*it2,'x');
	      add_edge(getIndex(i,*it2,'0'),id,1,0);
	      for(set<int>::iterator it = station[i][1].begin(); it != station[i][1].end();it++)
		{
		  if(*it >= *it2)
		    {
		      add_edge(id,getIndex(i,*it,'1'),1,0);
		    }
		}
	    }
	}

      for(set<int>::iterator it=station[1][1].begin();it!=station[1][1].end();it++)
	{
	  add_edge(0,getIndex(1,*it,'1'),inf,0);
	}

      for(set<int>::iterator it=station[n][1].begin();it!=station[n][1].end();it++)
	{
	  add_edge(getIndex(n,*it,'1'),last,1,0);
	}

      cin >> g;
      add_edge(last,last2,g,0);
      
      /*
      cout << "V = " << V << endl;
      rep(i,MAX_V)
	{
	  if(G[i].empty())continue;
	  cout << "from " << i << endl;
	  rep(j,G[i].size())
	    {
	      edge e = G[i][j];
	      cout << "(to,cap,cost,rev) = (" << e.to << "," << e.cap << "," << e.cost << "," << e.rev << ")" << endl; 
	    }
	  cout << "----" << endl;
	}
      cout << endl;
      */

      int ans =  min_cost_flow(0,last2,inf);
      if(g == G[last][G[last].size()-1].cap)cout << "0 0" << endl;
      else cout << g-G[last][G[last].size()-1].cap << " " << ans << endl;
      
    }
  return 0;
} 

Measured memory_bytes: 3536