#include <bits/stdc++.h>

#define REP(i,n) for(int i=0;i<(int)(n);i++)

using namespace std;
#define MAX_V 10000
int V;

typedef int Weight;
const Weight INF = 100000000;
// const Weight eps = 1e-8;

struct Edge{
  int src, dest;
  int cap, rev;
  Weight weight;
  bool operator < (const Edge &rhs) const {return weight > rhs.weight;}
};

typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;

Weight h[MAX_V];                // potential
Weight dist[MAX_V];             // minimum distance
int prevv[MAX_V], preve[MAX_V]; // previous vertex and edge

void add_edge(Graph &g, int src, int dest, int cap, Weight weight) {
  g[src].push_back((Edge){src, dest, cap, (int)g[dest].size(), weight});
  g[dest].push_back((Edge){dest, src, 0, (int)g[src].size() - 1, -weight});
}

Weight min_cost_flow(Graph &g, int s, int t, int f) {
  Weight res = 0; V = g.size();
  memset(h, 0, sizeof(h));
  typedef pair<Weight, int> P;
  while (f > 0) {
    priority_queue<P, vector<P>, greater<P> > que;
    fill(dist, dist + V, INF);
    dist[s] = 0;
    que.push(P(0, s));
    while (!que.empty()) {
      P p = que.top(); que.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.dest] > dist[v] + e.weight + h[v] - h[e.dest] /* + eps */) {
          dist[e.dest] = dist[v] + e.weight + h[v] - h[e.dest];
          prevv[e.dest] = v;
          preve[e.dest] = i;
          que.push(P(dist[e.dest], e.dest));
        }
      }
    }
    if (dist[t] == INF) return -1;
    REP(v, 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;
    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;
}

int main() {
  while(1){
    int n;
    cin>>n;
    if(!n)break;
    vector<vector<int>> arr(n);
    vector<vector<int>> dep(n);
    vector<vector<tuple<int,int,int>>> tr(n-1);
    vector<int> m(n-1);
    REP(i,n-1){
      cin>>m[i];
      REP(j,m[i]){
        int x,y,c;
        cin>>x>>y>>c;
        tr[i].emplace_back(x,y,c);
        dep[i].push_back(x);
        arr[i+1].push_back(y);
      }
    }
    dep.back().push_back(200000);
    Graph g;
    int sum = 0;
    vector<int> ind;
    REP(i,n) {
      sort(begin(arr[i]),end(arr[i]));
      sort(begin(dep[i]),end(dep[i]));
      arr[i].erase(unique(begin(arr[i]),end(arr[i])),end(arr[i]));
      dep[i].erase(unique(begin(dep[i]),end(dep[i])),end(dep[i]));
      int a = arr[i].size();
      int b = dep[i].size();
      REP(j,a+b) g.emplace_back();
      ind.push_back(sum);
      REP(j,a){
        auto itr = lower_bound(begin(dep[i]),end(dep[i]),arr[i][j]);
        if(itr != end(dep[i])){
          int k=itr-begin(dep[i]);
          add_edge(g, sum + j, sum + a + k, 1, 0);
        }
      }
      sum += a;
      ind.push_back(sum);
      REP(j,b-1){
        add_edge(g, sum + j, sum + j + 1, INF, 0);
      }
      sum += b;
    }
    REP(i,n-1){
      REP(j,m[i]){
        int x,y,c;
        tie(x,y,c)=tr[i][j];
        int di=lower_bound(begin(dep[i]),end(dep[i]),x)-begin(dep[i]);
        int ai=lower_bound(begin(arr[i+1]),end(arr[i+1]),y)-begin(arr[i+1]);
        add_edge(g, di + ind[i*2+1], ai + ind[(i+1)*2], INF, c);
      }
    }
    int k;
    cin>>k;
    int km = 0, cm = 0;
    REP(j,k+1) {
      if(!j) continue;
      auto cp = g;
      int ans = min_cost_flow(cp, 0, sum-1, j);
      if (ans < 0) break;
      km = j; cm = ans;
    }
    cout << km << ' ' << cm << endl;
  }
  return 0;
}

Measured memory_bytes: 1856