#include <bits/stdc++.h>
using namespace std;
#define int long long
#define stoi stoll
using pii=pair<int,int>;
#define all(c) begin(c),end(c)
#define rall(c) rbegin(c),rend(c)
#define fore(x,c) for(auto &&x:c)
#define rep(i,a,n) for(int i=a,i##len=(int)(n);i<i##len;++i)
#define rrep(i,n) for(int i=(int)(n);i>=0;--i)
#define sz(c) ((int)c.size())
#define contains(c,x) (c.find(x)!=end(c))
#define inseg(l,x,r) ((l)<=(x)&&(x)<(r))
#define dump(...)
#define pb push_back
#define _ 0
const signed INF_=1001001001; const long long INF=1001001001001001001LL;
const int DX[9]={0,1,0,-1,1,1,-1,-1,0},DY[9]={-1,0,1,0,-1,1,1,-1,0};
template<class T> ostream& operator<<(ostream &os,const vector<T> &v) {
    for (auto i = begin(v); i != end(v); i++) os<<*i<<(i==end(v)-1?"":" ");return os;}
template<class T> istream& operator>>(istream &is,vector<T> &v) {
    for (auto i = begin(v); i != end(v); i++) is>>*i;return is;}
template<class T,class U> istream& operator>>(istream &is, pair<T,U> &p) {
    is>>p.first>>p.second;return is;}
template<class T, class U> bool chmax(T &a,const U &b){return a<b?a=b,1:0;}
template<class T, class U> bool chmin(T &a,const U &b){return a>b?a=b,1:0;}
template <class T> void psum(T& c) {partial_sum(begin(c), end(c), begin(c));}
template<class T> using heap=priority_queue<T,vector<T>,greater<T>>;
struct before_main_function {
    before_main_function() {
        cin.tie(0); ios::sync_with_stdio(0);
        cout << setprecision(15) << fixed;
        // #define endl "\n"
    }
} before_main_function;
template <class T, typename U> void assign(T& container, int N, initializer_list<U> list) {
	for (auto e: list) {
		container[N] = e;
		N++;
	}
}

//------------------8<------------------------------------8<--------------------

int x, y, z, k;
vector<int> a, b, c;

void solver1() {
	vector<int> ab_arr(x*y);
	for (auto i=0; i<x; i++) {
	  for (auto j=0; j<y; j++) {
			ab_arr[i*y+j] = a[i] + b[j];
		}
	}
	sort(all(ab_arr), greater<int>());
	
	int xy = min(x*y, k);
	vector<int> abc_arr(xy*z);
	for (auto i=0; i<xy; i++) {
		for (auto j=0; j<z; j++) {
			abc_arr[i*z+j] = ab_arr[i] + c[j];
		}
	}

	sort(all(abc_arr), greater<int>());
	for (auto i=0; i<k; i++)
		cout << abc_arr[i] << endl;
}

int max_size() {
	int cnt = 0;
	for (auto i=1; i<=1000; i++) {
		for (auto j=1; j<=1000; j++) {
			for (auto l=1; l<=1000; l++) {
				if (i*j*l > 3000)
					break;
				cnt++;
			}	
		}
	}
	return cnt;
}
 
void solver2() {
	sort(all(a), greater<int>());
	sort(all(b), greater<int>());
	sort(all(c), greater<int>());

	int xyz = min(x*y*z, max_size());  // 後者は(x+1)*(y+1)*(z+1)<=k を覆う三角錐の体積
	vector<int> res(xyz, 0);
	int count = 0;
	for (auto i=0; i<x; i++) {
		for (auto j=0; j<y; j++) {
			for (auto l=0; l<z; l++) {
				if ((i+1)*(j+1)*(l+1) > k)
					break;
				res[count] = a[i] + b[j] + c[l];
				count++;
			}	
		}
	}
	res.resize(count);
	sort(all(res), greater<int>());
	for(auto i=0; i<k; i++)
		cout << res[i] << endl;
}

void solver3() {
	sort(all(a), greater<int>());
	sort(all(b), greater<int>());
	sort(all(c), greater<int>());
  auto compare = [](array<int, 4> l, array<int, 4> r){ return l[0] < r[0]; };
	priority_queue<int, vector<array<int, 4>>, decltype(compare)> pq(compare);
	
	set<array<int, 3>> mem;
	int i=0, j=0, l=0;
	array<int, 4> temp = {a[i]+b[j]+c[l], i, j, l};
	array<int, 3> comb = {i, j, l};
  mem.insert(comb);
	pq.push(temp);
	for (int m=0; m<k; m++) {
		cout << pq.top()[0] << endl;
		i = pq.top()[1];
		j = pq.top()[2];
		l = pq.top()[3];
		pq.pop();
		if (i+1 < x) {
			assign(comb, 0, {i+1, j, l});
			if (mem.find(comb) == mem.end()) {
				assign(temp, 0, {a[i+1]+b[j]+c[l], i+1, j, l});
				pq.push(temp);
				mem.insert(comb);
			}
		}
		if (j+1 < z) {
			assign(comb, 0, {i, j+1, l});
			if (mem.find(comb) == mem.end()) {
				assign(temp, 0, {a[i]+b[j+1]+c[l], i, j+1, l});
				pq.push(temp);
				mem.insert(comb);
			}
		}
		if (l+1 < z) {
			assign(comb, 0, {i, j, l+1});
			if (mem.find(comb) == mem.end()) {
				assign(temp, 0, {a[i]+b[j]+c[l+1], i, j, l+1});
				pq.push(temp);
				mem.insert(comb);
			}
		}
	}
}

bool is_more_K(int p) {  // p以上の要素数がk個以上かどうか
	int cnt = 0;
	for (auto i=0; i<x; i++) {
		for (auto j=0; j<y; j++) {
			for (auto l=0; l<z; l++) {
				if (a[i] + b[j] + c[l] < p) break;
				cnt++;
				if (cnt >= k) return true;
			}
		}
	}
	return false;
}

int search(int min, int max, function<bool(int)> bool_fn) { // bool_fnがfalseとなる最小の値を返す
	int mid;
	while (max-min > 1) {
		mid = (max + min) / 2;
		bool_fn(mid) ? min=mid : max=mid;
	}
	if (bool_fn(max)) max++;
	return max;
}

void solver4() {
	sort(all(a), greater<int>());
	sort(all(b), greater<int>());
	sort(all(c), greater<int>());
	
	int min = a[x-1] + b[y-1] + c[z-1];
	int max = a[0] + b[0] + c[0];

	//vector<int> range(max-min+1);
	//iota(all(range), 1);
	//auto iter = lower_bound(all(range), 1, [](int l, int no_use){ return is_more_K(l); });
	//  // 第一引数にコンテナ要素、第二引数にlower_boundの第二引数をとり、booleanを返すlambda関数をlower_boundの第三引数として渡す
	//	// lambda関数を適用すると(t, t, t, ..., f, f, ..., f)となるコンテナに対して、一番左のfの要素のiteratorを返す。
	//int border = *iter;
	int border = search(min, max, is_more_K);

	vector<int> res(k);
	int cnt=0;
	for (auto i=0; i<x; i++) {
		for (auto j=0; j<y; j++) {
			for (auto l=0; l<z; l++) {
				if (a[i]+b[j]+c[l] < border) break;
				res[cnt] = a[i] + b[j] + c[l];
				cnt++;
			}
		}
	}
	sort(all(res), greater<int>());
	for (auto i=0; i<cnt; i++) cout << res[i] << endl;
	for (auto i=cnt; i<k; i++) cout << border-1 << endl;
}

signed main() {
		cin >> x >> y >> z >> k;
		a.resize(x);
		b.resize(y);
		c.resize(z);
		cin >> a;
		cin >> b;
		cin >> c;

		solver4();

		return 0;
}


Measured memory_bytes: 384