#include <bits/stdc++.h>
#define rep(i,n) for (int i = 0; i < (n); ++i)

using namespace std;
typedef pair<int, int> P;
typedef long long ll;
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }

//最大公約数
ll gcd(ll x, ll y) {
    ll tmp = 0;
    if (x < y){
        tmp=x;
        x=y;
        y=tmp;
    }
    while (y > 0) {
        ll r = x % y;
        x = y;
        y = r;
        }
    return x;
}

//最大公倍数
ll lcm(ll x,ll y){
    return x/gcd(x,y)*y;
}

const int MAX = 1e6+1;
const ll MOD = 998244353;

long long fac[MAX], finv[MAX], inv[MAX];

// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD;
        inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
        finv[i] = finv[i - 1] * inv[i] % MOD;
    }
}

struct mint {
  ll x; // typedef long long ll;
    mint(ll x=0):x((x%MOD+MOD)%MOD){}
    mint operator-() const { return mint(-x);}
    mint& operator+=(const mint a) {
    if ((x += a.x) >= MOD) x -= MOD;
    return *this;
    }
    mint& operator-=(const mint a) {
    if ((x += MOD-a.x) >= MOD) x -= MOD;
    return *this;
    }
    mint& operator*=(const mint a) {
        (x *= a.x) %= MOD;
        return *this;
    }
    mint operator+(const mint a) const {
        mint res(*this);
        return res+=a;
    }
    mint operator-(const mint a) const {
        mint res(*this);
        return res-=a;
    }
    mint operator*(const mint a) const {
        mint res(*this);
        return res*=a;
    }
    mint pow(ll t) const {
        if (!t) return 1;
        mint a = pow(t>>1);
        a *= a;
        if (t&1) a *= *this;
        return a;
    }

    // for prime MOD
    mint inv() const {
        return pow(MOD-2);
    }
    mint& operator/=(const mint a) {
        return (*this) *= a.inv();
    }
    mint operator/(const mint a) const {
        mint res(*this);
        return res/=a;
    }
};

// 二項係数計算
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}


//階乗
ll kaijo(ll k){
    ll sum = 1;
    for (ll i = 1; i <= k; ++i)
    {
        sum *= i;
        sum%=1000000000+7;
    }
    return sum;
}

long long modpow(long long a, long long n, long long MOD) {
    long long res = 1;
    while (n > 0) {
        if (n & 1) res = res * a % MOD;
        a = a * a % MOD;
        n >>= 1;
    }
    return res;
}

//sieve(MAX);でベクトルIsPrimeに「MAXまでの数値の素数の真偽」を格納する。
struct Sieve {
    int n;
    vector<int> f, primes;
    Sieve(int n=1):n(n), f(n+1) {
        f[0] = f[1] = -1;
        for (ll i = 2; i <= n; ++i) {
        if (f[i]) continue;
        primes.push_back(i);
        f[i] = i;
        for (ll j = i*i; j <= n; j += i) {
            if (!f[j]) f[j] = i;
        }
        }
    }
    bool isPrime(int x) { return f[x] == x;}
    vector<int> factorList(int x) {
        vector<int> res;
        while (x != 1) {
        res.push_back(f[x]);
        x /= f[x];
        }
        return res;
    }
    vector<P> factor(int x) {
        vector<int> fl = factorList(x);
        if (fl.size() == 0) return {};
        vector<P> res(1, P(fl[0], 0));
        for (int p : fl) {
        if (res.back().first == p) {
            res.back().second++;
        } else {
            res.emplace_back(p, 1);
        }
        }
        return res;
    }
};
struct UnionFind {
    vector<int> par;
    UnionFind(int n) : par(n, -1) { }
    int root(int x) {
        if (par[x] < 0) return x;
        else return par[x] = root(par[x]);
    }
    bool issame(int x, int y) {
        return root(x) == root(y);
    }
    bool merge(int x, int y) {
        x = root(x); y = root(y);
        if (x == y) return false;
        if (par[x] > par[y]) swap(x, y); // merge technique
        par[x] += par[y];
        par[y] = x;
        return true;
    }
    ll size(int x) {
        return -par[root(x)];
    }
};

ll count(int n, int a){
    ll bunshi = 1;
    for(int i = 0; i < a; i++){
        bunshi*=(n-i);
        bunshi%=MOD;
    }
    ll bunbo = 1;
    for(int i = 1; i < a+1; i++){
        bunbo*=i;
        bunbo%=MOD;
    }
    bunbo = modpow(bunbo,MOD-2,MOD);
    // cout<<(bunshi*bunbo)%MOD<<endl;
    return (bunshi*bunbo)%MOD;
}

// 約数列挙。約数をvector<ll>で返す。計算量はsqrt(n)。
vector<ll> divisor(ll n) {
    vector<ll> ret;
    for(ll i = 1; i * i <= n; i++) {
        if(n % i == 0) {
        ret.push_back(i);
        if(i * i != n) ret.push_back(n / i);
        }
    }
    sort(begin(ret), end(ret));
    return (ret);
}

// ここから開始
const ll INF = 1e18;
const double PI = 3.14159265358979323846264338327950;
int dx[] = {1,0,-1,0};
int dy[] = {0,1,0,-1};

bool used[1000][1000][1000];


int main(){
    int x,y,z,K;
    cin>>x>>y>>z>>K;
    vector<ll> a(x);
    vector<ll> b(y);
    vector<ll> c(z);
    rep(i,x) cin>>a[i];
    rep(i,y) cin>>b[i];
    rep(i,z) cin>>c[i];
    sort(a.begin(),a.end());
    sort(b.begin(),b.end());
    sort(c.begin(),c.end());
    reverse(a.begin(),a.end());
    reverse(b.begin(),b.end());
    reverse(c.begin(),c.end());

    // // DEBUG
    // rep(i,a.size()) cout<<a[i]<<" ";
    // cout<<endl;
    // rep(i,b.size()) cout<<b[i]<<" ";
    // cout<<endl;
    // rep(i,c.size()) cout<<c[i]<<" ";
    // cout<<endl;
    rep(i,x)rep(j,y)rep(k,z) used[i][j][k] = false;   
    used[0][0][0] = true;
    int mark[3] = {0,0,0};
    ll ans = a[0]+b[0]+c[0];
    priority_queue<pair<ll, tuple<int,int,int> > > pque;
    pque.push({ans,make_tuple(0,0,0)});
    for(int i = 0; i < K; i++){
        pair<ll, tuple<int,int,int> > now = pque.top();
        pque.pop();
        int xx = get<0>(now.second);
        int yy = get<1>(now.second);
        int zz = get<2>(now.second);
        // cout<<now.first<<" "<<xx<<" "<<yy<<" "<<zz<<" "<<endl;
        cout<<now.first<<endl;

        if(!used[xx+1][yy][zz]&&xx+1<x) {
            pque.push({a[xx+1]+b[yy]+c[zz],make_tuple(xx+1,yy,zz)});
            used[xx+1][yy][zz] = true;
        }
        if(!used[xx][yy+1][zz]&&yy+1<y){
            pque.push({a[xx]+b[yy+1]+c[zz],make_tuple(xx,yy+1,zz)});
            used[xx][yy+1][zz] = true;
        } 
        if(!used[xx][yy][zz+1]&&zz+1<z){
            pque.push({a[xx]+b[yy]+c[zz+1],make_tuple(xx,yy,zz+1)});
            used[xx][yy][zz+1] = true;
        } 
    }
    return 0;
}


Measured memory_bytes: 977536