#pragma GCC optimize("O3")

#include "bits/stdc++.h"
#include "ext/pb_ds/tree_policy.hpp"
#include "ext/pb_ds/assoc_container.hpp"
#include "ext/rope"

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef pair<int, int> pii;
#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define F0R(i, a) for(int i = 0; i < (a); ++i)
#define pb push_back
#define sz size
#define f first
#define s second

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;

struct custom_hash 
{
    static uint64_t splitmix64(uint64_t x) 
    {
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const 
    {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
class SegmentTree {
    private: 
        vector<int> st, A;
        int n;
        int left (int p) 
        { 
            return  p<<1; 
        } 
        int right(int p) 
        { 
            return (p<<1) + 1; 
        }
        void build(int p, int L, int R) 
        {
            if (L == R)
                st[p] = L;
            else 
            {
                build(left(p) , L, (L+R)/2);
                build(right(p), (L+R)/2 + 1, R);
                int p1 = st[left(p)], p2 = st[right(p)];
                st[p] = (A[p1] <= A[p2]) ? p1 : p2;
            } 
        }
        int rmq(int p, int L, int R, int i, int j) 
        {
            if (i >  R || j <  L) return -1;
            if (L >= i && R <= j) return st[p];
            int p1 = rmq(left(p), L, (L+R)/2, i, j);
            int p2 = rmq(right(p), (L+R)/2+1, R, i, j);
            if (p1 == -1) return p2;
            if (p2 == -1) return p1;
            return (A[p1] <= A[p2]) ? p1 : p2; 
        }
        int update(int p, int L, int R, int idx, int new_value) 
        {
            int i = idx, j = idx; 
            if (i > R || j < L) return st[p];
            if (L == i && R == j) 
            {
                A[i] = A[i] + new_value; 
                return st[p] = L;
            }
            int p1, p2;
            p1 = update(left(p), L, (L+R)/2, idx, new_value);
            p2 = update(right(p), (L+R)/2+1, R, idx, new_value);
            return st[p] = (A[p1] <= A[p2]) ? p1 : p2;
        }
    public:
        SegmentTree(const vector<int> &_A) 
        {
            A = _A; 
            n = (int)A.size();
            st.assign(4*n, 0);
            build(1, 0, n-1);
        }
        int rmq(int i, int j) 
        { 
            //returns value of an rmq (not index). 
            //Make everything in array negative and change this return to negative for max queries
            return rmq(1, 0, n-1, i, j); 
        }     
        int update(int i, int v) 
        {
            return update(1, 0, n-1, i, v); 
        }
};
int main()
{
    // freopen("input.txt", "r", stdin);
    // freopen("output.txt", "w", stdout);
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int n;
    cin >> n;
    vector<vector<int>> adj (n, vector<int>());
    F0R(i, n - 1)
    {
        int a, b;
        cin >> a >> b;
        a--; b--;
        adj[a].pb(b);
        adj[b].pb(a);
    }
    vector<int> tm (n);
    F0R(i, tm.sz()) tm[i] = adj[i].sz();
    SegmentTree st (tm);
    vector<int> c (n, 0);
    F0R(i, n) cin >> c[i];
    sort(c.begin(), c.end());
    vector<int> res (n, -1);
    F0R(i, c.sz())
    {
        int l = st.rmq(0, n);
        res[l] = c[i];
        st.update(l, 1e5);
        F0R(j, adj[l].sz())
        {
            st.update(adj[l][j], -1);
        }
    }
    ll r = 0;
    F0R(i, adj.sz())
    {
        F0R(j, adj[i].sz())
        {
            r += min(res[i], res[adj[i][j]]);
        }
    }
    cout << r/2 << "\n";
    F0R(i, res.sz())
    cout << res[i] << " ";
    return 0;
}

Measured memory_bytes: 1280