#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <stack>
#include <list>
#include <utility>
#include <vector>
#include <set>
#include <algorithm>
#include <cmath>
#include <climits>
#include <map>
#include <unordered_map>
#include <string.h>
#include<iomanip>
#include <iterator>
#include <locale>

#define all(a) a.begin(),a.end()
#define VV(T) vector<vector< T > >
#define rep(i,N) for(int i = 0; i <N; i++)
#define repsg(i,s,g) for(int i = s; i <g; i++)
#define name(x) #x


using namespace std;

const int INF = INT_MAX;
const long long INFL = 1LL<<40;
const double PI = atan(1)*4;
const long long MOD = pow(10,9)+7;
int dy[]={0, 0, 1, -1, 0};
int dx[]={1, -1, 0, 0, 0};

typedef long long ll,LL;
typedef vector<int> vint;
typedef vector<vector<int> > vvint;
typedef vector<long long> vll, vLL;
typedef vector<vector<long long> > vvll, vvLL;
typedef pair<int,int> pii;
typedef pair<LL, LL> pLL;


// vector入力
template<typename T>
istream& operator >> (istream& is, vector<T>& vec){
    for(T& x: vec) is >> x;
    return is;
}
// vector出力
template<typename T>
ostream& operator << (ostream& os, vector<T>& vec){
    for(int i=0; i<vec.size(); i++){
        os << vec[i] << ( i+1 == vec.size() ? "" : " " );
    }
    return os;
}


class summation{
public:
    ll sum;
    int iA;
    int iB;
    int iC;
    summation(ll s,int ia,int ib, int ic){
        this->sum = s;
        this->iA = ia;
        this->iB = ib;
        this->iC = ic;
    }

    };

bool operator< (const summation &s1, const summation &s2){
    return s1.sum < s2.sum;
};

set<ll> used;

int main() {
    
    int x,y,z,k;cin>>x>>y>>z>>k;
    vector<ll> a(x),b(y),c(z);
    cin>>a;
    cin>>b;
    cin>>c;
    
    sort(all(a),greater<ll>());
    sort(all(b),greater<ll>());
    sort(all(c),greater<ll>());
    
    priority_queue<summation> sum;
    int ia = 0, ib = 0, ic = 0;

    used.insert(ia + 10000*ib + 10000*10000*ic);
    summation temp(a[ia]+b[ib]+c[ic],ia,ib,ic);
    sum.push(temp);
    
    rep(n,k){
        summation top = sum.top();
        cout<<top.sum<<endl;
        sum.pop();
        
        int iA = top.iA;
        int iB = top.iB;
        int iC = top.iC;
        
        summation inp(top);
        if(iA + 1 <x && used.count(iA+1 + 10000*iB + 10000*10000*iC)==0 ){
            inp.sum = a[iA+1]+b[iB]+c[iC];inp.iA =iA+1;inp.iB = iB; inp.iC = iC;
            sum.push(inp);
            used.insert(iA+1 + 10000*iB + 10000*10000*iC);
        }
        if(iB+1<y&& used.count(iA + 10000*(iB+1) + 10000*10000*iC)==0 ){
            inp.sum = a[iA]+b[iB+1]+c[iC];inp.iA =iA;inp.iB = iB+1; inp.iC = iC;
            sum.push(inp);
            used.insert(iA + 10000*(iB+1) + 10000*10000*iC);
        }
        if(iC+1<z&& used.count(iA + 10000*iB + 10000*10000*(iC+1))==0 ){
            inp.sum = a[iA]+b[iB]+c[iC+1];inp.iA =iA;inp.iB = iB; inp.iC = iC+1;
            sum.push(inp);
            used.insert(iA +10000*iB + 10000*10000*(iC+1));
        }
        
    }
    
    return 0;
}


/*
 A,B,Cはソートしておける。
 0番目は自明に最も大きいものをそれぞれ取れば良い。 ia = 0, ib = 0, ic = 0
1番目は、A,B,Cのそれぞれで二番目に大きいものにするケースを計算して比較すればいい。3パターン
 e.g. ia = 1, ib = 0, ic = 0;
2番目は、1番目ですでに計算したもののあまり + 1番目で変更したものの三番目に大きいものの計算結果のなかから求めればいい。
 1番目で変更しなかったものをずらすと自明に値が小さくなるので、2番目の候補にはなれない。
 {ia = 0, ib = 0, ic = 0}, {ia = 1, ib = 0, ic = 0} ////{ia = 0,ib=1,ic=0}, {ia = 0, ib = 0, ic = 1}, {ia = 2, ib = 0, ic = 0}
 の中で三番目に大きいもの
 3番目は、
{ia = 0,ib=1,ic=0}, {ia = 0, ib = 0, ic = 1}, {ia = 2, ib = 0, ic = 0}からどう遷移したかで考える。
 前ステップで選択されたもの以外はそのまま残る。選択されたものについて、3通り試す必要がある。
 ...
 k番目は、k-1番目までで計算した候補のあまり + (前回選択されたものの遷移先)
 
 
 
 各ステップで候補が2個増えていく。priority queueで処理。
 
 -> uniqueなものだけ取り出してくる処理が必要なので、setで管理しておく。
 
 
 

 */


Measured memory_bytes: 768