#include <bits/stdc++.h>
using namespace std;
template <typename Arg1>
void __f(const char* name, Arg1&& arg1) {
  cout << name << " : " << arg1 << '\n';
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args) {
  const char* comma = strchr(names + 1, ',');
  cout.write(names, comma - names) << " : " << arg1 << " | ";
  __f(comma + 1, args...);
}
const long long int N = 1000005;
struct segmenttree {
  vector<long long int> st;
  void init(long long int _n) {
    st.clear();
    st.resize(4 * _n);
  }
  void build(long long int l, long long int r, long long int node) {
    if (l == r) {
      return;
    }
    long long int mid = (l + r) / 2;
    build(l, mid, node * 2 + 1);
    build(mid + 1, r, node * 2 + 2);
    st[node] = max(st[2 * node + 1], st[2 * node + 2]);
  }
  void update(long long int l, long long int r, long long int indup,
              long long int val, long long int node) {
    if (l == r) {
      st[node] = val;
      return;
    } else {
      long long int mid = (l + r) / 2;
      if (indup >= l && indup <= mid) {
        update(l, mid, indup, val, node * 2 + 1);
      } else {
        update(mid + 1, r, indup, val, node * 2 + 2);
      }
      st[node] = max(st[2 * node + 1], st[2 * node + 2]);
    }
  }
  long long int query(long long int si, long long int se, long long int l,
                      long long int r, long long int node) {
    if (se < l || si > r || l > r) {
      return INT_MIN;
    }
    if (si >= l && se <= r) {
      return st[node];
    }
    long long int mid = (si + se) / 2;
    long long int q1 = query(si, mid, l, r, node * 2 + 1);
    long long int q2 = query(mid + 1, se, l, r, node * 2 + 2);
    return max(q1, q2);
  }
};
segmenttree tree[N];
long long int sz[N], res[N], mx[N], n, m;
vector<long long int> pos[N];
long long int give(long long int row, long long int pos) {
  long long int mn, mx, ret;
  if (pos < sz[row]) {
    mn = max(0ll, pos - (m - sz[row])), mx = pos;
    if ((m - 1) - pos >= sz[row])
      ret = 0;
    else
      ret = INT_MIN;
  } else {
    pos = sz[row] - (m - pos);
    mn = pos, mx = max(sz[row] - 1, pos + (m - sz[row]));
    if (pos >= sz[row])
      ret = INT_MIN;
    else
      ret = 0;
  }
  return max(ret, tree[row].query(0, sz[row] - 1, mn, mx, 0));
}
int32_t main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  {
    long long int i, j, k, ans = 0, cnt = 0, sum = 0;
    cin >> n >> m;
    for (i = 0; i < n; i++) {
      cin >> sz[i];
      tree[i].init(sz[i]);
      for (j = 0; j < sz[i]; j++) {
        long long int x;
        cin >> x;
        mx[i] = max(mx[i], x);
        tree[i].update(0, sz[i] - 1, j, x, 0);
      }
      for (j = 0; j < sz[i]; j++) pos[j].push_back(i);
      for (j = max(sz[i], (m - sz[i])); j < m; j++) pos[j].push_back(i);
    }
    for (i = 0; i < n; i++) {
      ans += mx[i];
    }
    for (i = 0; i < m; i++) {
      res[i] = ans;
      for (auto x : pos[i]) {
        res[i] -= mx[x];
        res[i] += give(x, i);
      }
    }
    for (i = 0; i < m; i++) {
      cout << res[i] << " ";
    }
  }
}
