Problem:
Problem L: Tree Fragments
Problem
あいちゃんは、$N$個の頂点と$N-1$本の辺からなる木$T$を持っている。各頂点には$1$から$N$までの番号と、正の整数の重みがついている。
次の$Q$回のクエリに順に答えよ。
$1 \le a_i,b_i \le N$($a_i \ne b_i$)が与えられるので、$T$の$a_i$-$b_i$パス上の頂点とそれに接続する辺を取り除いてできる、いくつかの連結成分の中で、重みが最大となる連結成分の重みを出力する。そのような連結成分が1つもない場合、0と出力する。
ただし、連結成分の重みはその連結成分に含まれる頂点の重みの和で定義される。
Input
入力は以下の形式で与えられる。
$N$
$w_1$ $w_2$ ... $w_N$
$u_1$ $v_1$
$u_2$ $v_2$
...
$u_{N-1}$ $v_{N-1}$
$Q$
$a_1$ $b_1$
$a_2$ $b_2$
...
$a_Q$ $b_Q$
入力はすべて整数で与えられる。
1行目に$T$の頂点数$N$が与えられる。
2行目に頂点$i$($1 \le i \le N$)の重み$w_i$が空白区切りで与えられる。
3行目以降の$N$-1行に辺$_i$($1 \le i \le N-1$)の端点$u_i,v_i$が空白区切りで与えられる。
$N$+2行目にクエリの数$Q$が与えられる。
$N$+3行目以降の$Q$行に、クエリ$_i$($1 \le i \le Q$)を表す$a_i,b_i$が空白区切りで与えられる。
Constraints
入力は以下の条件を満たす。
$2 \le N \le 10^5$
$1 \le Q \le 10^5$
$1 \le w_i \le 10^8$($1 \le i \le N$)
$1 \le u_i,v_i \le N$($1 \le i \le N-1$)
$u_i \ne v_i$
$i \ne j$なら$(u_i,v_i) \ne (u_j,v_j)$かつ$(u_i,v_i) \ne (v_j, u_j)$
$1 \le a_i,b_i \le N$($1 \le i \le Q$)
$a_i \ne b_i$
Ouput
クエリ毎に、0または重みが最大となる連結成分の重みを1行に出力する。
Sample Input 1
10
1 2 3 4 5 6 7 8 9 10
1 2
2 3
3 4
3 5
2 6
6 7
2 8
8 9
8 10
3
3 8
7 1
7 10
Sample Output 1
13
27
12
Sample Input 2
5
1 2 3 4 5
1 2
2 3
3 4
4 5
3
1 2
1 5
2 4
Sample Output 2
12
0
5
Sample Input 3
15
3 8 4 2 6 5 1 2 10 3 4 2 6 1 1
1 2
2 3
3 4
3 5
2 6
6 7
6 8
1 9
9 10
10 11
10 12
9 13
13 14
13 15
5
1 1
2 7
6 10
1 15
3 4
Sample Output 3
28
30
12
28
46

Submitted solutions:

code_snippet: #include <bits/stdc++.h>

using namespace std;

const long long LOG = 20;

struct Node {
    long long m1, m2, m3;
};

vector<vector<long long>> parent, max_up;
vector<long long> p, par, glub, maxb;
vector<Node> mxs;

void dfs(long long v, long long PRED, vector<vector<long long>> &g, vector<long long> &a) {
    par[v] = PRED;
    p[v] += a[v];
    multiset<long long> st;
    for (auto i: g[v]) {
        if (i != PRED) dfs(i, v, g, a);
        if (i != PRED) p[v] += p[i];
        if (i != PRED) st.insert(p[i]);
        while (st.size() >= 4) st.erase(st.begin());
    }
    while (st.size() != 3) st.insert(0);
    Node o;
    o.m3 = *st.begin();
    st.erase(st.begin());
    o.m2 = *st.begin();
    st.erase(st.begin());
    o.m1 = *st.begin();
    st.erase(st.begin());
    mxs[v] = o;
}

void dfs2(long long u, long long p, vector<vector<long long>> &g) {
    parent[u][0] = p;
    glub[u] = 0;
    glub[u] = glub[p] + 1;
    max_up[u][0] = max(maxb[u], maxb[p]);
    for (long long i = 1; i < LOG; ++i) {
        parent[u][i] = parent[parent[u][i - 1]][i - 1];
        max_up[u][i] = max(max_up[u][i - 1], max_up[parent[u][i - 1]][i - 1]);
    }
    for (long long v: g[u]) {
        if (v != p) {
            dfs2(v, u, g);
        }
    }
}

long long lca(long long u, long long v) {
    if (glub[u] < glub[v]) swap(u, v);
    for (long long i = LOG - 1; i >= 0; --i) {
        if (glub[u] - (1 << i) >= glub[v]) {
            u = parent[u][i];
        }
    }
    if (u == v) return u;
    for (long long i = LOG - 1; i >= 0; --i) {
        if (parent[u][i] != parent[v][i]) {
            u = parent[u][i];
            v = parent[v][i];
        }
    }
    return parent[u][0];
}

long long p_on_s(long long v, long long s) {
    for (long long i = LOG; i >= 0; i--) {
        if ((1 << i) <= s) {
            v = parent[v][i];
            s -= (1 << i);
        }
    }
    return v;
}

long long GET(long long u, long long v) {
    long long ancestor = lca(u, v);
    long long max_val = 0;
    for (long long i = LOG - 1; i >= 0; --i) {
        if (glub[u] - (1 << i) >= glub[ancestor]) {
            max_val = max(max_val, max_up[u][i]);
            u = parent[u][i];
        }
    }
    max_val = max(max_val, maxb[u]);
    for (long long i = LOG - 1; i >= 0; --i) {
        if (glub[v] - (1 << i) >= glub[ancestor]) {
            max_val = max(max_val, max_up[v][i]);
            v = parent[v][i];
        }
    }
    max_val = max(max_val, maxb[v]);
    return max_val;
}

signed main() {
    long long n;
    cin >> n;
    vector<long long> a(n);
    for (long long i = 0; i < n; i++) cin >> a[i];
    long long FULL = 0;
    for (auto i: a) FULL += i;
    vector<vector<long long>> g(n);
    for (long long i = 0; i < n - 1; i++) {
        long long X, Y;
        cin >> X >> Y;
        X--;
        Y--;
        g[X].push_back(Y);
        g[Y].push_back(X);
    }
    p.resize(n, 0);
    par.resize(n, 0);
    mxs.resize(n, {0, 0});
    dfs(0, -1, g, a);
    maxb.resize(n, 0);
    parent.resize(n, vector<long long>(LOG));
    max_up.resize(n, vector<long long>(LOG));
    glub.resize(n, 0);
    for (long long i = 1; i < n; i++) {
        if (mxs[par[i]].m1 == p[i]) maxb[i] = mxs[par[i]].m2;
        else maxb[i] = mxs[par[i]].m1;
    }
    dfs2(0, 0, g);
    long long q;
    cin >> q;
    while (q--) {
        long long x, y;
        cin >> x >> y;
        x--;
        y--;
        long long z = lca(x, y);
        if (z == x || z == y) {
            if (z == y) swap(x, y);
            cout << max({GET(x, y), FULL - p[z], mxs[y].m1}) << "\n";
            continue;
        }
        long long xx, yy;
        if (glub[x] - glub[z] == 1) xx = -1;
        else xx = p_on_s(x, glub[x] - glub[z] - 2);
        if (glub[y] - glub[z] == 1) yy = -1;
        else yy = p_on_s(y, glub[y] - glub[z] - 2);
        long long xxx = p_on_s(x, glub[x] - glub[z] - 1);
        long long yyy = p_on_s(y, glub[y] - glub[z] - 1);
        multiset<long long, greater<>> otb;
        long long getmax_x = 0;
        long long getmax_y = 0;
        if (xx != -1) getmax_x = GET(x, xx);
        if (yy != -1) getmax_y = GET(y, yy);
        multiset<long long, greater<>> mxs_s;
        mxs_s.insert(mxs[z].m1);
        mxs_s.insert(mxs[z].m2);
        mxs_s.insert(mxs[z].m3);
        if (mxs_s.find(p[xxx]) != mxs_s.end()) mxs_s.erase(mxs_s.find(p[xxx]));
        if (mxs_s.find(p[yyy]) != mxs_s.end()) mxs_s.erase(mxs_s.find(p[yyy]));
        cout << max({*mxs_s.begin(), getmax_x, getmax_y, mxs[y].m1, mxs[x].m1, FULL - p[lca(x, y)]}) << "\n";
    }
}
accuracy: 1
time_ms: 290
memory_kb: 54536
final_rank: 13

code_snippet: #include <bits/stdc++.h>
#define int long long
using namespace std;

const int MAXN = 1e5 + 5;
const int LOG = 20;

struct Node {
    int m1, m2, m3, m4;
};

vector<int> maxb;
int parent[MAXN][LOG];
int depth[MAXN];
int max_up[MAXN][LOG];
vector<int> p, par;
vector<Node> mxs;

void dfs(int v, int PRED, vector<vector<int>> &g, vector<int> &a) {
    par[v] = PRED;
    p[v] += a[v];
    multiset<int> st;
    for (auto i: g[v]) {
        if (i != PRED) dfs(i, v, g, a);
        if (i != PRED) p[v] += p[i];
        if (i != PRED) st.insert(p[i]);
        while (st.size() >= 4) st.erase(st.begin());
    }
    while (st.size() != 3) st.insert(0);
    Node o;
    o.m3 = *st.begin();
    st.erase(st.begin());
    o.m2 = *st.begin();
    st.erase(st.begin());
    o.m1 = *st.begin();
    st.erase(st.begin());
    mxs[v] = o;
}

void dfs2(int u, int p, vector<vector<int>> &g) {
    parent[u][0] = p;
    depth[u] = 0;
    depth[u] = depth[p] + 1;
    max_up[u][0] = max(maxb[u], maxb[p]);
    for (int i = 1; i < LOG; ++i) {
        parent[u][i] = parent[parent[u][i - 1]][i - 1];
        max_up[u][i] = max(max_up[u][i - 1], max_up[parent[u][i - 1]][i - 1]);
    }
    for (int v: g[u]) {
        if (v != p) {
            dfs2(v, u, g);
        }
    }
}

int lca(int u, int v) {
    if (depth[u] < depth[v]) swap(u, v);
    for (int i = LOG - 1; i >= 0; --i) {
        if (depth[u] - (1 << i) >= depth[v]) {
            u = parent[u][i];
        }
    }
    if (u == v) return u;
    for (int i = LOG - 1; i >= 0; --i) {
        if (parent[u][i] != parent[v][i]) {
            u = parent[u][i];
            v = parent[v][i];
        }
    }
    return parent[u][0];
}

int p_on_s(int v, int s) {
    for (int i = LOG; i >= 0; i--) {
        if ((1 << i) <= s) {
            v = parent[v][i];
            s -= (1 << i);
        }
    }
    return v;
}

int get_max_on_path(int u, int v) {
    int ancestor = lca(u, v);
    int max_val = 0;
    for (int i = LOG - 1; i >= 0; --i) {
        if (depth[u] - (1 << i) >= depth[ancestor]) {
            max_val = max(max_val, max_up[u][i]);
            u = parent[u][i];
        }
    }
    max_val = max(max_val, maxb[u]);
    for (int i = LOG - 1; i >= 0; --i) {
        if (depth[v] - (1 << i) >= depth[ancestor]) {
            max_val = max(max_val, max_up[v][i]);
            v = parent[v][i];
        }
    }
    max_val = max(max_val, maxb[v]);
    return max_val;
}

signed main() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];
    int FULL = 0;
    for (auto i: a) FULL += i;
    vector<vector<int>> g(n);
    for (int i = 0; i < n - 1; i++) {
        int X, Y;
        cin >> X >> Y;
        X--;
        Y--;
        g[X].push_back(Y);
        g[Y].push_back(X);
    }
    p.resize(n, 0);
    par.resize(n);
    mxs.resize(n, {0, 0});
    dfs(0, -1, g, a);
    maxb.resize(n, 0);
    for (int i = 1; i < n; i++) {
        if (mxs[par[i]].m1 == p[i]) maxb[i] = mxs[par[i]].m2;
        else maxb[i] = mxs[par[i]].m1;
    }
    dfs2(0, 0, g);
    int q;
    cin >> q;
    while (q--) {
        int x, y;
        cin >> x >> y;
        x--;
        y--;
        int z = lca(x, y);
        if(z==x || z==y){
            if(z==y) swap(x,y);
            cout<<max({get_max_on_path(x,y),FULL-p[z],mxs[y].m1})<<"\n";
            continue;
        }
        int xx,yy;
        if(depth[x]-depth[z]==1) xx=-1;
        else xx = p_on_s(x, depth[x] - depth[z] - 2);
        if(depth[y]-depth[z]==1) yy=-1;
        else yy = p_on_s(y, depth[y] - depth[z] - 2);
        int xxx=p_on_s(x, depth[x] - depth[z] - 1);
        int yyy=p_on_s(y, depth[y] - depth[z] - 1);

        multiset<int,greater<>> otb;
        int getmax_x=0;
        int getmax_y=0;
        if(xx!=-1)getmax_x = get_max_on_path(x,xx);
        if(yy!=-1)getmax_y = get_max_on_path(y,yy);

        multiset<int,greater<>> mxs_s;
        mxs_s.insert(mxs[z].m1);
        mxs_s.insert(mxs[z].m2);
        mxs_s.insert(mxs[z].m3);
        if(mxs_s.find(p[xxx])!=mxs_s.end()) mxs_s.erase(mxs_s.find(p[xxx]));
        if(mxs_s.find(p[yyy])!=mxs_s.end()) mxs_s.erase(mxs_s.find(p[yyy]));
        cout<<max({*mxs_s.begin(),getmax_x,getmax_y,mxs[y].m1,mxs[x].m1,FULL - p[lca(x, y)]})<<"\n";
    }
}
accuracy: 1
time_ms: 250
memory_kb: 47612
final_rank: 7

code_snippet: #include <bits/stdc++.h>
#define int long long
using namespace std;

const int MAXN = 1e5 + 5;
const int LOG = 20;

struct Node {
    int m1, m2, m3, m4;
};

vector<int> maxb;
int parent[MAXN][LOG];
int depth[MAXN];
int max_up[MAXN][LOG];

vector<int> p, par;
vector<Node> mxs;

Node merge(Node &n1, Node &n2) {
    vector<int> y;
    y = {n1.m1, n1.m2, n1.m3, n1.m4, n2.m1, n2.m2, n2.m3, n2.m4};
    sort(y.rbegin(), y.rend());
    Node ans;
    ans.m1 = y[0];
    ans.m2 = y[1];
    ans.m3 = y[2];
    ans.m4 = y[3];
    return ans;
}

void dfs(int v, int PRED, vector<vector<int>> &g, vector<int> &a) {
    par[v] = PRED;
    p[v] += a[v];
    multiset<int> st;
    for (auto i: g[v]) {
        if (i != PRED) dfs(i, v, g, a);
        if (i != PRED) p[v] += p[i];
        if (i != PRED) st.insert(p[i]);
        while (st.size() >= 5) st.erase(st.begin());
    }
    while (st.size() != 4) st.insert(0);
    Node o;
    o.m4 = *st.begin();
    st.erase(st.begin());
    o.m3 = *st.begin();
    st.erase(st.begin());
    o.m2 = *st.begin();
    st.erase(st.begin());
    o.m1 = *st.begin();
    st.erase(st.begin());
    mxs[v] = o;
}

void dfs2(int u, int p, vector<vector<int>> &g) {
    parent[u][0] = p;
    depth[u] = 0;
    depth[u] = depth[p] + 1;
    max_up[u][0] = max(maxb[u], maxb[p]); // Инициализация для первого предка

    for (int i = 1; i < LOG; ++i) {
        //cout<<u<<' '<<i<<"\n";
        parent[u][i] = parent[parent[u][i - 1]][i - 1];
        max_up[u][i] = max(max_up[u][i - 1], max_up[parent[u][i - 1]][i - 1]);
    }

    for (int v: g[u]) {
        if (v != p) {
            dfs2(v, u, g);
        }
    }
}

int lca(int u, int v) {
    if (depth[u] < depth[v]) swap(u, v);

    // Поднимаем u до уровня v
    for (int i = LOG - 1; i >= 0; --i) {
        if (depth[u] - (1 << i) >= depth[v]) {
            u = parent[u][i];
        }
    }

    if (u == v) return u;

    // Поднимаем вместе до LCA
    for (int i = LOG - 1; i >= 0; --i) {
        if (parent[u][i] != parent[v][i]) {
            u = parent[u][i];
            v = parent[v][i];
        }
    }

    return parent[u][0];
}

int p_on_s(int v, int s) {
    for (int i = LOG; i >= 0; i--) {
        if ((1 << i) <= s) {
            v = parent[v][i];
            s -= (1 << i);
        }
    }
    return v;
}

int get_max_on_path(int u, int v) {
    int ancestor = lca(u, v);
    int max_val = 0;

    // Поднимаемся от u до LCA
    for (int i = LOG - 1; i >= 0; --i) {
        if (depth[u] - (1 << i) >= depth[ancestor]) {
            max_val = max(max_val, max_up[u][i]);
            u = parent[u][i];
        }
    }
    max_val = max(max_val, maxb[u]);

    // Поднимаемся от v до LCA
    for (int i = LOG - 1; i >= 0; --i) {
        if (depth[v] - (1 << i) >= depth[ancestor]) {
            max_val = max(max_val, max_up[v][i]);
            v = parent[v][i];
        }
    }
    max_val = max(max_val, maxb[v]);

    return max_val;
}


signed main() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];
    int FULL = 0;
    for (auto i: a) FULL += i;
    vector<vector<int>> g(n);
    for (int i = 0; i < n - 1; i++) {
        int X, Y;
        cin >> X >> Y;
        X--;
        Y--;
        g[X].push_back(Y);
        g[Y].push_back(X);
    }
    p.resize(n, 0);
    par.resize(n);
    mxs.resize(n, {0, 0});
    dfs(0, -1, g, a);
    maxb.resize(n, 0);
    for (int i = 1; i < n; i++) {
        if (mxs[par[i]].m1 == p[i]) maxb[i] = mxs[par[i]].m2;
        else maxb[i] = mxs[par[i]].m1;
    }
    dfs2(0, 0, g);
    int q;
    cin >> q;
    //for (int i = 0; i < n; i++) cout << maxb[i] << "\n";

    while (q--) {
        int x, y;
        cin >> x >> y;
        x--;
        y--;
        int z = lca(x, y);
        if(z==x || z==y){
            if(z==y) swap(x,y);
            cout<<max({get_max_on_path(x,y),FULL-p[z],mxs[y].m1})<<"\n";
            continue;
        }
        int xx,yy;
        if(depth[x]-depth[z]==1) xx=-1;
        else xx = p_on_s(x, depth[x] - depth[z] - 2);
        if(depth[y]-depth[z]==1) yy=-1;
        else yy = p_on_s(y, depth[y] - depth[z] - 2);
        int xxx=p_on_s(x, depth[x] - depth[z] - 1);
        int yyy=p_on_s(y, depth[y] - depth[z] - 1);

        multiset<int,greater<>> otb;
        int getmax_x=0;
        int getmax_y=0;
        if(xx!=-1)getmax_x = get_max_on_path(x,xx);
        if(yy!=-1)getmax_y = get_max_on_path(y,yy);

        multiset<int,greater<>> mxs_s;
        mxs_s.insert(mxs[z].m1);
        mxs_s.insert(mxs[z].m2);
        mxs_s.insert(mxs[z].m3);
        if(mxs_s.find(p[xxx])!=mxs_s.end()) mxs_s.erase(mxs_s.find(p[xxx]));
        if(mxs_s.find(p[yyy])!=mxs_s.end()) mxs_s.erase(mxs_s.find(p[yyy]));
        cout<<max({*mxs_s.begin(),getmax_x,getmax_y,mxs[y].m1,mxs[x].m1,FULL - p[lca(x, y)]})<<"\n";
        //cout<<*mxs_s.begin()<<' '<<getmax_x<<' '<<getmax_y<<' '<<mxs[y].m1<<' '<<mxs[x].m1<<' '<<FULL - p[lca(x, y)]<<"\n";
//        cout << get_max_on_path(x, y) << ' ' << mxs[x].m1 << ' ' << mxs[y].m1 << ' ' << FULL - p[lca(x, y)]
//             << "\n";
//        cout << max({get_max_on_path(x, y), mxs[x].m1, mxs[y].m1, FULL - p[lca(x, y)]}) << "\n";

    }
}
accuracy: 1
time_ms: 250
memory_kb: 47440
final_rank: 6

code_snippet: #include <bits/stdc++.h>

using namespace std;

const int MAXN = 1e5 + 5;
const int LOG = 20;

struct Node {
    int m1, m2, m3, m4;
};

vector<int> maxb;
int parent[MAXN][LOG];
int depth[MAXN];
int max_up[MAXN][LOG];

vector<int> p, par;
vector<Node> mxs;

Node merge(Node &n1, Node &n2) {
    vector<int> y;
    y = {n1.m1, n1.m2, n1.m3, n1.m4, n2.m1, n2.m2, n2.m3, n2.m4};
    sort(y.rbegin(), y.rend());
    Node ans;
    ans.m1 = y[0];
    ans.m2 = y[1];
    ans.m3 = y[2];
    ans.m4 = y[3];
    return ans;
}

void dfs(int v, int PRED, vector<vector<int>> &g, vector<int> &a) {
    par[v] = PRED;
    p[v] += a[v];
    multiset<int> st;
    for (auto i: g[v]) {
        if (i != PRED) dfs(i, v, g, a);
        if (i != PRED) p[v] += p[i];
        if (i != PRED) st.insert(p[i]);
        while (st.size() >= 5) st.erase(st.begin());
    }
    while (st.size() != 4) st.insert(0);
    Node o;
    o.m4 = *st.begin();
    st.erase(st.begin());
    o.m3 = *st.begin();
    st.erase(st.begin());
    o.m2 = *st.begin();
    st.erase(st.begin());
    o.m1 = *st.begin();
    st.erase(st.begin());
    mxs[v] = o;
}

void dfs2(int u, int p, vector<vector<int>> &g) {
    parent[u][0] = p;
    depth[u] = 0;
    depth[u] = depth[p] + 1;
    max_up[u][0] = max(maxb[u], maxb[p]); // Инициализация для первого предка

    for (int i = 1; i < LOG; ++i) {
        //cout<<u<<' '<<i<<"\n";
        parent[u][i] = parent[parent[u][i - 1]][i - 1];
        max_up[u][i] = max(max_up[u][i - 1], max_up[parent[u][i - 1]][i - 1]);
    }

    for (int v: g[u]) {
        if (v != p) {
            dfs2(v, u, g);
        }
    }
}

int lca(int u, int v) {
    if (depth[u] < depth[v]) swap(u, v);

    // Поднимаем u до уровня v
    for (int i = LOG - 1; i >= 0; --i) {
        if (depth[u] - (1 << i) >= depth[v]) {
            u = parent[u][i];
        }
    }

    if (u == v) return u;

    // Поднимаем вместе до LCA
    for (int i = LOG - 1; i >= 0; --i) {
        if (parent[u][i] != parent[v][i]) {
            u = parent[u][i];
            v = parent[v][i];
        }
    }

    return parent[u][0];
}

int p_on_s(int v, int s) {
    for (int i = LOG; i >= 0; i--) {
        if ((1 << i) <= s) {
            v = parent[v][i];
            s -= (1 << i);
        }
    }
    return v;
}

int get_max_on_path(int u, int v) {
    int ancestor = lca(u, v);
    int max_val = 0;

    // Поднимаемся от u до LCA
    for (int i = LOG - 1; i >= 0; --i) {
        if (depth[u] - (1 << i) >= depth[ancestor]) {
            max_val = max(max_val, max_up[u][i]);
            u = parent[u][i];
        }
    }
    max_val = max(max_val, maxb[u]);

    // Поднимаемся от v до LCA
    for (int i = LOG - 1; i >= 0; --i) {
        if (depth[v] - (1 << i) >= depth[ancestor]) {
            max_val = max(max_val, max_up[v][i]);
            v = parent[v][i];
        }
    }
    max_val = max(max_val, maxb[v]);

    return max_val;
}


signed main() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++) cin >> a[i];
    int FULL = 0;
    for (auto i: a) FULL += i;
    vector<vector<int>> g(n);
    for (int i = 0; i < n - 1; i++) {
        int X, Y;
        cin >> X >> Y;
        X--;
        Y--;
        g[X].push_back(Y);
        g[Y].push_back(X);
    }
    p.resize(n, 0);
    par.resize(n);
    mxs.resize(n, {0, 0});
    dfs(0, -1, g, a);
    maxb.resize(n, 0);
    for (int i = 1; i < n; i++) {
        if (mxs[par[i]].m1 == p[i]) maxb[i] = mxs[par[i]].m2;
        else maxb[i] = mxs[par[i]].m1;
    }
    dfs2(0, 0, g);
    int q;
    cin >> q;
    //for (int i = 0; i < n; i++) cout << maxb[i] << "\n";

    while (q--) {
        int x, y;
        cin >> x >> y;
        x--;
        y--;
        int z = lca(x, y);
        if(z==x || z==y){
            if(z==y) swap(x,y);
            cout<<max({get_max_on_path(x,y),FULL-p[z],mxs[y].m1})<<"\n";
            continue;
        }
        int xx,yy;
        if(depth[x]-depth[z]==1) xx=-1;
        else xx = p_on_s(x, depth[x] - depth[z] - 2);
        if(depth[y]-depth[z]==1) yy=-1;
        else yy = p_on_s(y, depth[y] - depth[z] - 2);
        int xxx=p_on_s(x, depth[x] - depth[z] - 1);
        int yyy=p_on_s(y, depth[y] - depth[z] - 1);

        multiset<int,greater<>> otb;
        int getmax_x=0;
        int getmax_y=0;
        if(xx!=-1)getmax_x = get_max_on_path(x,xx);
        if(yy!=-1)getmax_y = get_max_on_path(y,yy);

        multiset<int,greater<>> mxs_s;
        mxs_s.insert(mxs[z].m1);
        mxs_s.insert(mxs[z].m2);
        mxs_s.insert(mxs[z].m3);
        if(mxs_s.find(p[xxx])!=mxs_s.end()) mxs_s.erase(mxs_s.find(p[xxx]));
        if(mxs_s.find(p[yyy])!=mxs_s.end()) mxs_s.erase(mxs_s.find(p[yyy]));
        cout<<max({*mxs_s.begin(),getmax_x,getmax_y,mxs[y].m1,mxs[x].m1,FULL - p[lca(x, y)]})<<"\n";
        //cout<<*mxs_s.begin()<<' '<<getmax_x<<' '<<getmax_y<<' '<<mxs[y].m1<<' '<<mxs[x].m1<<' '<<FULL - p[lca(x, y)]<<"\n";
//        cout << get_max_on_path(x, y) << ' ' << mxs[x].m1 << ' ' << mxs[y].m1 << ' ' << FULL - p[lca(x, y)]
//             << "\n";
//        cout << max({get_max_on_path(x, y), mxs[x].m1, mxs[y].m1, FULL - p[lca(x, y)]}) << "\n";

    }
}
accuracy: 0.48936170212765956
time_ms: 60
memory_kb: 22840
final_rank: 19

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=3037

#include<bits/stdc++.h>
using namespace std;

#define call_from_test
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}

template<typename Vertex, typename Cluster, size_t N>
struct TopTree{
  enum Type { Compress, Rake, Edge };
  struct Node{
    Vertex* vs[2];
    Cluster dat;
    Node* p;
    Node* q;
    Node* ch[2];
    bool rev,guard;
    Type type;
    Node(){p=q=nullptr;rev=guard=false;}
  };

  inline static array<Vertex, 2*N> pool_vertex;
  inline static size_t ptr_vertex = 0;

  inline static array<Node, 4*N> pool_node;
  inline static size_t ptr_node = 0;

  Cluster id;

  template<typename ...Args>
  inline Vertex* create(Args ...args){
    auto t=&pool_vertex[ptr_vertex++];
    auto dummy=&pool_vertex[ptr_vertex++];
    *t=Vertex(forward<Args>(args)...);
    link(t,id,dummy);
    return t;
  }

  Node* recycle=nullptr;
  inline void dispose_node(Node* t){
    t->p=recycle;
    recycle=t;
  }

  inline Node* get_new_node(){
    if(recycle) return new(exchange(recycle,recycle->p)) Node;
    return &(pool_node[ptr_node++]);
  }

  inline Node* edge(Vertex* u,Cluster w,Vertex* v){
    auto t=get_new_node();
    t->vs[0]=u;t->vs[1]=v;t->dat=w;
    t->type=Type::Edge;
    return pushup(t);
  }

  inline Node* compress(Node* l,Node* r){
    auto t=get_new_node();
    t->ch[0]=l;t->ch[1]=r;
    t->type=Type::Compress;
    return pushup(t);
  }

  inline Node* rake(Node* l,Node* r){
    auto t=get_new_node();
    t->ch[0]=l;t->ch[1]=r;
    t->type=Type::Rake;
    return pushup(t);
  }

  int parent_dir(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->guard) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  int parent_dir_ignore_guard(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  inline Node* pushup(Node* const t){
    Node* const l=t->ch[0];
    Node* const r=t->ch[1];

    if(t->type==Type::Compress){
      assert(l->vs[1]==r->vs[0]);
      t->vs[0]=l->vs[0];
      t->vs[1]=r->vs[1];

      Cluster lf=l->dat;
      if(t->q){
        assert(l->vs[1]==t->q->vs[1]);
        lf=Cluster::rake(l->dat,t->q->dat);
      }
      t->dat=Cluster::compress(lf,r->vs[0],r->dat);

      l->vs[1]->handle=t;
    }

    if(t->type==Type::Rake){
      propagate(t);
      assert(l->vs[1]==r->vs[1]);
      t->vs[0]=l->vs[0];
      t->vs[1]=l->vs[1];
      t->dat=Cluster::rake(l->dat,r->dat);
    }else{
      if(!t->p){
        t->vs[0]->handle=t;
        t->vs[1]->handle=t;
      }else if(t->p->type==Type::Compress){
        if(parent_dir(t)==-1)
          t->vs[0]->handle=t;
      }else if(t->p->type==Type::Rake){
        t->vs[0]->handle=t;
      }
    }
    return t;
  }

  inline void toggle(Node* t){
    if(t->type==Type::Edge){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
    }else if(t->type==Type::Compress){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
      t->rev^=true;
    }else if(t->type==Type::Rake){
    }else abort();
  }

  inline void propagate(Node* t){
    if(t->type==Type::Compress){
      if(t->rev){
        assert(t->ch[0] and t->ch[1]);
        swap(t->ch[0],t->ch[1]);
        toggle(t->ch[0]);
        toggle(t->ch[1]);
        t->rev=false;
      }
    }
  }

  void set_toggle(Node* v){
    toggle(v);propagate(v);
  }

  void pushdown(Node* t){
    if(!t) return;
    pushdown(t->p);
    propagate(t);
  }

  void rotate(Node* t,Node* x,size_t dir){
    Node* y=x->p;
    int par=parent_dir_ignore_guard(x);
    propagate(t->ch[dir]);
    x->ch[dir^1]=t->ch[dir];
    t->ch[dir]->p=x;
    t->ch[dir]=x;
    x->p=t;
    t->p=y;
    if(~par) y->ch[par]=t;
    else if(y and y->type==Type::Compress) y->q=t;
    pushup(x);pushup(t);
    if(y and !y->guard) pushup(y);
  }

  void splay(Node* t){
    assert(t->type!=Type::Edge);
    propagate(t);

    while(~parent_dir(t)){
      Node* q=t->p;
      if(q->type!=t->type) break;
      if(~parent_dir(q) and q->p and q->p->type==q->type){
        Node* r=q->p;
        if(r->p) propagate(r->p);
        propagate(r);propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        int rq_dir=parent_dir(q);
        if(rq_dir==qt_dir){
          rotate(q,r,rq_dir^1);
          rotate(t,q,qt_dir^1);
        }else{
          rotate(t,q,qt_dir^1);
          rotate(t,r,rq_dir^1);
        }
      }else{
        if(q->p) propagate(q->p);
        propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        rotate(t,q,qt_dir^1);
      }
    }
  }

  Node* expose(Node* t){
    pushdown(t);
    while(true){
      assert(t->type!=Type::Rake);
      if(t->type==Type::Compress) splay(t);
      Node* n=nullptr;
      {
        Node* p=t->p;
        if(!p) break;
        if(p->type==Type::Rake){
          propagate(p);
          splay(p);
          n=p->p;
        }
        if(p->type==Type::Compress){
          propagate(p);
          if(p->guard and ~parent_dir_ignore_guard(t)) break;
          n=p;
        }
      }
      splay(n);
      int dir=parent_dir_ignore_guard(n);
      if(dir==-1 or n->p->type==Type::Rake) dir=0;

      Node* const c=n->ch[dir];
      if(dir==1){
        set_toggle(c);
        set_toggle(t);
      }
      int n_dir=parent_dir(t);
      if(~n_dir){
        Node* const r=t->p;
        propagate(c);
        propagate(r);
        r->ch[n_dir]=c;
        c->p=r;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(r);
        pushup(t);pushup(n);
        splay(r);
      }else{
        propagate(c);
        n->q=c;
        c->p=n;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(t);pushup(n);
      }
      if(t->type==Type::Edge) t=n;
    }
    return t;
  }

  Node* expose(Vertex* v){
    return expose((Node*)(v->handle));
  }

  void soft_expose(Vertex* u,Vertex* v){
    pushdown((Node*)u->handle);
    pushdown((Node*)v->handle);
    Node* rt=expose(u);

    if(u->handle==v->handle){
      if(rt->vs[1]==u or rt->vs[0]==v)
        set_toggle(rt);
      return;
    }

    rt->guard=true;
    Node* soft=expose(v);
    rt->guard=false;

    pushup(rt);
    if(parent_dir(soft)==0) set_toggle(rt);
  }

  void bring(Node* rt){
    Node* rk=rt->q;
    if(!rk){
      Node* ll=rt->ch[0];
      dispose_node(ll->p);
      ll->p=nullptr;
      pushup(ll);
    }else if(rk->type==Type::Compress or rk->type==Type::Edge){
      Node* nr=rk;
      set_toggle(nr);
      rt->ch[1]=nr;
      nr->p=rt;
      rt->q=nullptr;

      pushup(nr);pushup(rt);
    }else if(rk->type==Type::Rake){
      propagate(rk);
      while(rk->ch[1]->type==Type::Rake){
        propagate(rk->ch[1]);
        rk=rk->ch[1];
      }
      pushdown(rk);

      rt->guard=true;
      splay(rk);
      rt->guard=false;

      Node* ll=rk->ch[0];
      Node* rr=rk->ch[1];
      propagate(ll);
      set_toggle(rr);

      rt->ch[1]=rr;
      rr->p=rt;

      rt->q=ll;
      ll->p=rt;

      dispose_node(rk);
      pushup(ll);pushup(rr);pushup(rt);
    }
  }

  Node* link(Vertex* u,Cluster w,Vertex* v){
    if(!u->handle and !v->handle) return edge(u,w,v);

    Node* nnu=(Node*)u->handle;
    Node* nnv=(Node*)v->handle;
    Node* ee=edge(u,w,v);
    Node* ll=nullptr;

    assert(nnv);
    Node* vv=expose(nnv);
    propagate(vv);
    if(vv->vs[1]==v) set_toggle(vv);
    if(vv->vs[0]==v){
      Node* nv=compress(ee,vv);
      ee->p=nv;
      pushup(ee);
      vv->p=nv;
      pushup(vv);pushup(nv);
      ll=nv;
    }else{
      Node* nv=vv;
      Node* ch=nv->ch[0];
      propagate(ch);
      nv->ch[0]=ee;
      ee->p=nv;
      pushup(ee);

      Node* bt=nv->q;
      Node* rk=nullptr;
      if(bt){
        propagate(bt);
        rk=rake(bt,ch);
        bt->p=rk;
        ch->p=rk;
        pushup(bt);pushup(ch);
      }else{
        rk=ch;
      }
      nv->q=rk;
      rk->p=nv;
      pushup(rk);pushup(nv);
      ll=nv;
    }

    assert(nnu);
    Node* uu=expose(nnu);
    propagate(uu);
    if(uu->vs[0]==u) set_toggle(uu);
    if(uu->vs[1]==u){
      Node* tp=compress(uu,ll);
      uu->p=tp;
      ll->p=tp;
      pushup(uu);pushup(ll);pushup(tp);
    }else{
      Node* nu=uu;
      Node* ch=nu->ch[1];
      toggle(ch);
      propagate(ch);

      nu->ch[1]=ll;
      ll->p=nu;
      pushup(ll);

      Node* al=nu->q;
      Node* rk=nullptr;
      if(al){
        propagate(al);
        rk=rake(al,ch);
        al->p=rk;
        ch->p=rk;
        pushup(al);pushup(ch);
      }else{
        rk=ch;
      }
      nu->q=rk;
      rk->p=nu;
      pushup(rk);pushup(nu);
    }
    return ee;
  }

  void cut(Vertex* u,Vertex *v){
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    Node* rr=rt->ch[1];
    rr->p=nullptr;
    set_toggle(rr);
    assert(rr->ch[1]->type==Type::Edge);
    dispose_node(rr->ch[1]);
    bring(rr);bring(rt);
  }

  Node* path(Vertex* u,Vertex* v){
    assert(u!=v);
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    propagate(rt->ch[1]);
    return rt->ch[1]->ch[0];
  }

  void set_vertex(Vertex* u,Vertex v){
    auto t=expose(u);
    *u=v;
    pushup(t);
  }

  void set_edge(Vertex* u,Vertex* v,const Cluster &w){
    auto t=path(u,v);
    assert(t->type==Type::Edge);
    t->dat=w;
    while(t) pushup(t),t=t->p;
  }

  Cluster get_path(Vertex* u,Vertex* v){
    return path(u,v)->dat;
  }

  Cluster get_subtree(Vertex* v){
    return expose(v)->dat;
  }

  // subtree of v when p is root
  Cluster get_subtree(Vertex* p,Vertex* v){
    Node* t=path(p,v);
    Cluster res=t->p->ch[1]->dat;
    res.toggle();
    Node* rk=t->p->q;
    if(t->p->q){
      assert(rk->vs[1]==t->p->ch[1]->vs[0]);
      res=Cluster::rake(res,rk->dat);
    }
    return res;
  }
};

#undef call_from_test

using ll = long long;
struct Vertex{
  void* handle;
  ll val;
  Vertex(ll val=0):handle(nullptr),val(val){}
};

struct Cluster{
  ll sm,md,chd,ma;
  Cluster():sm(0),md(0),chd(0),ma(0){}
  void toggle(){}
  static Cluster compress(Cluster x,Vertex *v,Cluster y){
    Cluster z;
    z.sm=x.sm+(v->val)+y.sm;
    z.md=max({x.md,x.chd,y.md});
    z.ma=x.sm+(v->val)+y.sm;
    return z;
  }
  static Cluster rake(Cluster x,Cluster y){
    x.sm+=y.sm;
    x.chd=max({x.chd,y.chd,y.ma});
    return x;
  }
};

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  const char newl = '\n';

  int n;
  cin>>n;
  vector<int> ws(n);
  for(int i=0;i<n;i++) cin>>ws[i];

  const size_t N = 1e5 + 10;
  TopTree<Vertex, Cluster, N> G;

  vector<Vertex*> vs(n);
  for(int i=0;i<n;i++) vs[i]=G.create(ws[i]);

  for(int i=1;i<n;i++){
    int u,v;
    cin>>u>>v;
    u--;v--;
    G.link(vs[u],Cluster(),vs[v]);
  }

  Vertex* da=G.create(0);
  Vertex* db=G.create(0);

  int q;
  cin>>q;
  for(int i=0;i<q;i++){
    int a,b;
    cin>>a>>b;
    a--;b--;

    G.link(da,Cluster(),vs[a]);
    G.link(db,Cluster(),vs[b]);

    cout<<G.get_path(da,db).md<<newl;

    G.cut(da,vs[a]);
    G.cut(db,vs[b]);
  }
  return 0;
}
accuracy: 1
time_ms: 350
memory_kb: 43296
final_rank: 12

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=3037

#include<bits/stdc++.h>
using namespace std;

#define call_from_test
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}

template<typename Vertex, typename Cluster, size_t N>
struct TopTree{
  enum Type { Compress, Rake, Edge };
  struct Node{
    Vertex* vs[2];
    Cluster dat;
    Node* p;
    Node* q;
    Node* ch[2];
    bool rev,guard;
    Type type;
    Node(){p=q=nullptr;rev=guard=false;}
  };

  inline static array<Vertex, 2*N> pool_vertex;
  inline static size_t ptr_vertex = 0;

  inline static array<Node, 4*N> pool_node;
  inline static size_t ptr_node = 0;

  Cluster id;

  template<typename ...Args>
  inline Vertex* create(Args ...args){
    auto t=&pool_vertex[ptr_vertex++];
    auto dummy=&pool_vertex[ptr_vertex++];
    *t=Vertex(forward<Args>(args)...);
    link(t,id,dummy);
    return t;
  }

  Node* recycle=nullptr;
  inline void dispose_node(Node* t){
    t->p=recycle;
    recycle=t;
  }

  inline Node* get_new_node(){
    if(recycle) return new(exchange(recycle,recycle->p)) Node;
    return &(pool_node[ptr_node++]);
  }

  inline Node* edge(Vertex* u,Cluster w,Vertex* v){
    auto t=get_new_node();
    t->vs[0]=u;t->vs[1]=v;t->dat=w;
    t->type=Type::Edge;
    return pushup(t);
  }

  inline Node* compress(Node* l,Node* r){
    auto t=get_new_node();
    t->ch[0]=l;t->ch[1]=r;
    t->type=Type::Compress;
    return pushup(t);
  }

  inline Node* rake(Node* l,Node* r){
    auto t=get_new_node();
    t->ch[0]=l;t->ch[1]=r;
    t->type=Type::Rake;
    return pushup(t);
  }

  int parent_dir(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->guard) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  int parent_dir_ignore_guard(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  inline Node* pushup(Node* const t){
    Node* const l=t->ch[0];
    Node* const r=t->ch[1];

    if(t->type==Type::Compress){
      assert(l->vs[1]==r->vs[0]);
      t->vs[0]=l->vs[0];
      t->vs[1]=r->vs[1];

      Cluster lf=l->dat;
      if(t->q){
        assert(l->vs[1]==t->q->vs[1]);
        lf=Cluster::rake(l->dat,t->q->dat);
      }
      t->dat=Cluster::compress(lf,r->vs[0],r->dat);

      l->vs[1]->handle=t;
    }

    if(t->type==Type::Rake){
      propagate(t);
      assert(l->vs[1]==r->vs[1]);
      t->vs[0]=l->vs[0];
      t->vs[1]=l->vs[1];
      t->dat=Cluster::rake(l->dat,r->dat);
    }else{
      if(!t->p){
        t->vs[0]->handle=t;
        t->vs[1]->handle=t;
      }else if(t->p->type==Type::Compress){
        if(parent_dir(t)==-1)
          t->vs[0]->handle=t;
      }else if(t->p->type==Type::Rake){
        t->vs[0]->handle=t;
      }
    }
    return t;
  }

  inline void toggle(Node* t){
    if(t->type==Type::Edge){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
    }else if(t->type==Type::Compress){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
      t->rev^=true;
    }else if(t->type==Type::Rake){
    }else abort();
  }

  inline void propagate(Node* t){
    if(t->type==Type::Compress){
      if(t->rev){
        assert(t->ch[0] and t->ch[1]);
        swap(t->ch[0],t->ch[1]);
        toggle(t->ch[0]);
        toggle(t->ch[1]);
        t->rev=false;
      }
    }
  }

  void set_toggle(Node* v){
    toggle(v);propagate(v);
  }

  void pushdown(Node* t){
    if(!t) return;
    pushdown(t->p);
    propagate(t);
  }

  void rotate(Node* t,Node* x,size_t dir){
    Node* y=x->p;
    int par=parent_dir_ignore_guard(x);
    propagate(t->ch[dir]);
    x->ch[dir^1]=t->ch[dir];
    t->ch[dir]->p=x;
    t->ch[dir]=x;
    x->p=t;
    t->p=y;
    if(~par) y->ch[par]=t;
    else if(y and y->type==Type::Compress) y->q=t;
    pushup(x);pushup(t);
    if(y and !y->guard) pushup(y);
  }

  void splay(Node* t){
    assert(t->type!=Type::Edge);
    propagate(t);

    while(~parent_dir(t)){
      Node* q=t->p;
      if(q->type!=t->type) break;
      if(~parent_dir(q) and q->p and q->p->type==q->type){
        Node* r=q->p;
        if(r->p) propagate(r->p);
        propagate(r);propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        int rq_dir=parent_dir(q);
        if(rq_dir==qt_dir){
          rotate(q,r,rq_dir^1);
          rotate(t,q,qt_dir^1);
        }else{
          rotate(t,q,qt_dir^1);
          rotate(t,r,rq_dir^1);
        }
      }else{
        if(q->p) propagate(q->p);
        propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        rotate(t,q,qt_dir^1);
      }
    }
  }

  Node* expose(Node* t){
    pushdown(t);
    while(true){
      assert(t->type!=Type::Rake);
      if(t->type==Type::Compress) splay(t);
      Node* n=nullptr;
      {
        Node* p=t->p;
        if(!p) break;
        if(p->type==Type::Rake){
          propagate(p);
          splay(p);
          n=p->p;
        }
        if(p->type==Type::Compress){
          propagate(p);
          if(p->guard and ~parent_dir_ignore_guard(t)) break;
          n=p;
        }
      }
      splay(n);
      int dir=parent_dir_ignore_guard(n);
      if(dir==-1 or n->p->type==Type::Rake) dir=0;

      Node* const c=n->ch[dir];
      if(dir==1){
        set_toggle(c);
        set_toggle(t);
      }
      int n_dir=parent_dir(t);
      if(~n_dir){
        Node* const r=t->p;
        propagate(c);
        propagate(r);
        r->ch[n_dir]=c;
        c->p=r;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(r);
        pushup(t);pushup(n);
        splay(r);
      }else{
        propagate(c);
        n->q=c;
        c->p=n;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(t);pushup(n);
      }
      if(t->type==Type::Edge) t=n;
    }
    return t;
  }

  Node* expose(Vertex* v){
    return expose((Node*)(v->handle));
  }

  void soft_expose(Vertex* u,Vertex* v){
    pushdown((Node*)u->handle);
    pushdown((Node*)v->handle);
    Node* rt=expose(u);

    if(u->handle==v->handle){
      if(rt->vs[1]==u or rt->vs[0]==v)
        set_toggle(rt);
      return;
    }

    rt->guard=true;
    Node* soft=expose(v);
    rt->guard=false;

    pushup(rt);
    if(parent_dir(soft)==0) set_toggle(rt);
  }

  void bring(Node* rt){
    Node* rk=rt->q;
    if(!rk){
      Node* ll=rt->ch[0];
      dispose_node(ll->p);
      ll->p=nullptr;
      pushup(ll);
    }else if(rk->type==Type::Compress or rk->type==Type::Edge){
      Node* nr=rk;
      set_toggle(nr);
      rt->ch[1]=nr;
      nr->p=rt;
      rt->q=nullptr;

      pushup(nr);pushup(rt);
    }else if(rk->type==Type::Rake){
      propagate(rk);
      while(rk->ch[1]->type==Type::Rake){
        propagate(rk->ch[1]);
        rk=rk->ch[1];
      }
      pushdown(rk);

      rt->guard=true;
      splay(rk);
      rt->guard=false;

      Node* ll=rk->ch[0];
      Node* rr=rk->ch[1];
      propagate(ll);
      set_toggle(rr);

      rt->ch[1]=rr;
      rr->p=rt;

      rt->q=ll;
      ll->p=rt;

      dispose_node(rk);
      pushup(ll);pushup(rr);pushup(rt);
    }
  }

  Node* link(Vertex* u,Cluster w,Vertex* v){
    if(!u->handle and !v->handle) return edge(u,w,v);

    Node* nnu=(Node*)u->handle;
    Node* nnv=(Node*)v->handle;
    Node* ee=edge(u,w,v);
    Node* ll=nullptr;

    assert(nnv);
    Node* vv=expose(nnv);
    propagate(vv);
    if(vv->vs[1]==v) set_toggle(vv);
    if(vv->vs[0]==v){
      Node* nv=compress(ee,vv);
      ee->p=nv;
      pushup(ee);
      vv->p=nv;
      pushup(vv);pushup(nv);
      ll=nv;
    }else{
      Node* nv=vv;
      Node* ch=nv->ch[0];
      propagate(ch);
      nv->ch[0]=ee;
      ee->p=nv;
      pushup(ee);

      Node* bt=nv->q;
      Node* rk=nullptr;
      if(bt){
        propagate(bt);
        rk=rake(bt,ch);
        bt->p=rk;
        ch->p=rk;
        pushup(bt);pushup(ch);
      }else{
        rk=ch;
      }
      nv->q=rk;
      rk->p=nv;
      pushup(rk);pushup(nv);
      ll=nv;
    }

    assert(nnu);
    Node* uu=expose(nnu);
    propagate(uu);
    if(uu->vs[0]==u) set_toggle(uu);
    if(uu->vs[1]==u){
      Node* tp=compress(uu,ll);
      uu->p=tp;
      ll->p=tp;
      pushup(uu);pushup(ll);pushup(tp);
    }else{
      Node* nu=uu;
      Node* ch=nu->ch[1];
      toggle(ch);
      propagate(ch);

      nu->ch[1]=ll;
      ll->p=nu;
      pushup(ll);

      Node* al=nu->q;
      Node* rk=nullptr;
      if(al){
        propagate(al);
        rk=rake(al,ch);
        al->p=rk;
        ch->p=rk;
        pushup(al);pushup(ch);
      }else{
        rk=ch;
      }
      nu->q=rk;
      rk->p=nu;
      pushup(rk);pushup(nu);
    }
    return ee;
  }

  void cut(Vertex* u,Vertex *v){
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    Node* rr=rt->ch[1];
    rr->p=nullptr;
    set_toggle(rr);
    assert(rr->ch[1]->type==Type::Edge);
    dispose_node(rr->ch[1]);
    bring(rr);bring(rt);
  }

  Node* path(Vertex* u,Vertex* v){
    assert(u!=v);
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    propagate(rt->ch[1]);
    return rt->ch[1]->ch[0];
  }

  void set_vertex(Vertex* u,Vertex v){
    auto t=expose(u);
    *u=v;
    pushup(t);
  }

  void set_edge(Vertex* u,Vertex* v,const Cluster &w){
    auto t=path(u,v);
    assert(t->type==Type::Edge);
    t->dat=w;
    while(t) pushup(t),t=t->p;
  }

  Cluster get_path(Vertex* u,Vertex* v){
    return path(u,v)->dat;
  }

  Cluster get_subtree(Vertex* v){
    return expose(v)->dat;
  }

  // subtree of v when p is root
  Cluster get_subtree(Vertex* p,Vertex* v){
    Node* t=path(p,v);
    Cluster res=t->p->ch[1]->dat;
    res.toggle();
    Node* rk=t->p->q;
    if(t->p->q){
      assert(rk->vs[1]==t->p->ch[1]->vs[0]);
      res=Cluster::rake(res,rk->dat);
    }
    return res;
  }
};

#undef call_from_test

using ll = long long;
struct Vertex{
  void* handle;
  ll val;
  Vertex(ll val=0):handle(nullptr),val(val){}
};

struct Cluster{
  ll sm,md,chd,ma;
  Cluster():sm(0),md(0),chd(0),ma(0){}
  void toggle(){}
  static Cluster compress(Cluster x,Vertex *v,Cluster y){
    Cluster z;
    z.sm=x.sm+(v->val)+y.sm;
    z.md=max({x.md,x.chd,y.md});
    z.ma=x.sm+(v->val)+y.sm;
    return z;
  }
  static Cluster rake(Cluster x,Cluster y){
    x.sm+=y.sm;
    x.chd=max({x.chd,y.chd,y.ma});
    return x;
  }
};

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  const char newl = '\n';

  int n;
  cin>>n;
  vector<int> ws(n);
  for(int i=0;i<n;i++) cin>>ws[i];

  const size_t N = 1e5;
  TopTree<Vertex, Cluster, N> G;

  vector<Vertex*> vs(n);
  for(int i=0;i<n;i++) vs[i]=G.create(ws[i]);

  for(int i=1;i<n;i++){
    int u,v;
    cin>>u>>v;
    u--;v--;
    G.link(vs[u],Cluster(),vs[v]);
  }

  int q;
  cin>>q;
  for(int i=0;i<q;i++){
    int a,b;
    cin>>a>>b;
    a--;b--;
    ll res=G.get_path(vs[a],vs[b]).md;
    auto ab=G.get_subtree(vs[a],vs[b]);
    auto ba=G.get_subtree(vs[b],vs[a]);
    chmax(res,max(ab.chd,ab.ma));
    chmax(res,max(ba.chd,ba.ma));
    cout<<res<<newl;
  }
  return 0;
}
accuracy: 1
time_ms: 330
memory_kb: 43240
final_rank: 11

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=3037

#include<bits/stdc++.h>
using namespace std;

#define call_from_test
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}

template<typename Vertex, typename Cluster, size_t N>
struct TopTree{
  enum Type { Compress, Rake, Edge };
  struct Node{
    Vertex* vs[2];
    Cluster dat;
    Node* p;
    Node* q;
    Node* ch[2];
    bool rev,guard;
    Type type;
    Node():p(nullptr),q(nullptr),rev(false),guard(false){}
  };

  inline static array<Vertex, 2*N> pool_vertex;
  inline static size_t ptr_vertex = 0;

  inline static array<Node, 4*N> pool_node;
  inline static size_t ptr_node = 0;

  Cluster id;

  inline Vertex* create(Vertex v=Vertex()){
    auto t=&pool_vertex[ptr_vertex++];
    auto dummy=&pool_vertex[ptr_vertex++];
    *t=v;
    link(t,id,dummy);
    return t;
  }

  Node* recycle=nullptr;
  inline void dispose_node(Node* t){
    t->p=recycle;
    recycle=t;
  }

  inline Node* get_new_node(){
    if(recycle) return new(exchange(recycle,recycle->p)) Node;
    return &(pool_node[ptr_node++]);
  }

  inline Node* edge(Vertex* u,Cluster w,Vertex* v){
    auto t=get_new_node();
    t->vs[0]=u;t->vs[1]=v;t->dat=w;t->type=Type::Edge;
    return pushup(t);
  }

  inline Node* compress(Node* l,Node* r){
    auto t=get_new_node();
    t->ch[0]=l;t->ch[1]=r;t->type=Type::Compress;
    return pushup(t);
  }

  inline Node* rake(Node* l,Node* r){
    auto t=get_new_node();
    t->ch[0]=l;t->ch[1]=r;t->type=Type::Rake;
    return pushup(t);
  }

  int parent_dir(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->guard) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  int parent_dir_ignore_guard(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  inline Node* pushup(Node* const t){
    Node* const l=t->ch[0];
    Node* const r=t->ch[1];

    if(t->type==Type::Compress){
      assert(l->vs[1]==r->vs[0]);
      t->vs[0]=l->vs[0];
      t->vs[1]=r->vs[1];

      Cluster lf=l->dat;
      if(t->q){
        assert(l->vs[1]==t->q->vs[1]);
        lf=Cluster::rake(l->dat,t->q->dat);
      }
      t->dat=Cluster::compress(lf,r->vs[0],r->dat);

      l->vs[1]->handle=t;
    }

    if(t->type==Type::Rake){
      propagate(t);
      assert(l->vs[1]==r->vs[1]);
      t->vs[0]=l->vs[0];
      t->vs[1]=l->vs[1];
      t->dat=Cluster::rake(l->dat,r->dat);
    }else{
      if(!t->p){
        t->vs[0]->handle=t;
        t->vs[1]->handle=t;
      }else if(t->p->type==Type::Compress){
        if(parent_dir(t)==-1)
          t->vs[0]->handle=t;
      }else if(t->p->type==Type::Rake){
        t->vs[0]->handle=t;
      }
    }
    return t;
  }

  inline void toggle(Node* t){
    if(t->type==Type::Edge){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
    }else if(t->type==Type::Compress){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
      t->rev^=true;
    }else if(t->type==Type::Rake){
    }else abort();
  }

  inline void propagate(Node* t){
    if(t->type==Type::Compress){
      if(t->rev){
        assert(t->ch[0] and t->ch[1]);
        swap(t->ch[0],t->ch[1]);
        toggle(t->ch[0]);
        toggle(t->ch[1]);
        t->rev=false;
      }
    }
  }

  void set_toggle(Node* v){
    toggle(v);propagate(v);
  }

  void pushdown(Node* t){
    if(!t) return;
    pushdown(t->p);
    propagate(t);
  }

  void rotate(Node* t,Node* x,size_t dir){
    Node* y=x->p;
    int par=parent_dir_ignore_guard(x);
    propagate(t->ch[dir]);
    x->ch[dir^1]=t->ch[dir];
    t->ch[dir]->p=x;
    t->ch[dir]=x;
    x->p=t;
    t->p=y;
    if(~par) y->ch[par]=t;
    else if(y and y->type==Type::Compress) y->q=t;
    pushup(x);pushup(t);
    if(y and !y->guard) pushup(y);
  }

  void splay(Node* t){
    assert(t->type!=Type::Edge);
    propagate(t);

    while(~parent_dir(t)){
      Node* q=t->p;
      if(q->type!=t->type) break;
      if(~parent_dir(q) and q->p and q->p->type==q->type){
        Node* r=q->p;
        if(r->p) propagate(r->p);
        propagate(r);propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        int rq_dir=parent_dir(q);
        if(rq_dir==qt_dir){
          rotate(q,r,rq_dir^1);
          rotate(t,q,qt_dir^1);
        }else{
          rotate(t,q,qt_dir^1);
          rotate(t,r,rq_dir^1);
        }
      }else{
        if(q->p) propagate(q->p);
        propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        rotate(t,q,qt_dir^1);
      }
    }
  }

  Node* expose(Node* t){
    pushdown(t);
    while(true){
      assert(t->type!=Type::Rake);
      if(t->type==Type::Compress) splay(t);
      Node* n=nullptr;
      {
        Node* p=t->p;
        if(!p) break;
        if(p->type==Type::Rake){
          propagate(p);
          splay(p);
          n=p->p;
        }
        if(p->type==Type::Compress){
          propagate(p);
          if(p->guard and ~parent_dir_ignore_guard(t)) break;
          n=p;
        }
      }
      splay(n);
      int dir=parent_dir_ignore_guard(n);
      if(dir==-1 or n->p->type==Type::Rake) dir=0;

      Node* const c=n->ch[dir];
      if(dir==1){
        set_toggle(c);
        set_toggle(t);
      }
      int n_dir=parent_dir(t);
      if(~n_dir){
        Node* const r=t->p;
        propagate(c);
        propagate(r);
        r->ch[n_dir]=c;
        c->p=r;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(r);pushup(t);pushup(n);
        splay(r);
      }else{
        propagate(c);
        n->q=c;
        c->p=n;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(t);pushup(n);
      }
      if(t->type==Type::Edge) t=n;
    }
    return t;
  }

  Node* expose(Vertex* v){
    return expose((Node*)(v->handle));
  }

  void soft_expose(Vertex* u,Vertex* v){
    pushdown((Node*)u->handle);
    pushdown((Node*)v->handle);
    Node* rt=expose(u);

    if(u->handle==v->handle){
      if(rt->vs[1]==u or rt->vs[0]==v)
        set_toggle(rt);
      return;
    }

    rt->guard=true;
    Node* soft=expose(v);
    rt->guard=false;

    pushup(rt);
    if(parent_dir(soft)==0) set_toggle(rt);
  }

  void bring(Node* rt){
    Node* rk=rt->q;
    if(!rk){
      Node* ll=rt->ch[0];
      dispose_node(ll->p);
      ll->p=nullptr;
      pushup(ll);
    }else if(rk->type==Type::Compress or rk->type==Type::Edge){
      propagate(rk);

      Node* nr=rk;
      set_toggle(nr);
      rt->ch[1]=nr;
      nr->p=rt;
      rt->q=nullptr;

      pushup(nr);pushup(rt);
    }else if(rk->type==Type::Rake){
      propagate(rk);
      while(rk->ch[1]->type==Type::Rake){
        propagate(rk->ch[1]);
        rk=rk->ch[1];
      }
      pushdown(rk);

      rt->guard=true;
      splay(rk);
      rt->guard=false;

      Node* ll=rk->ch[0];
      Node* rr=rk->ch[1];
      propagate(ll);
      set_toggle(rr);

      rt->ch[1]=rr;
      rr->p=rt;

      rt->q=ll;
      ll->p=rt;

      pushup(ll);pushup(rr);pushup(rt);
    }
  }

  Node* link(Vertex* u,Cluster w,Vertex* v){
    if(!u->handle and !v->handle) return edge(u,w,v);

    Node* nnu=(Node*)u->handle;
    Node* nnv=(Node*)v->handle;
    Node* ee=edge(u,w,v);
    Node* ll=nullptr;

    assert(nnv);
    Node* vv=expose(nnv);
    propagate(vv);
    if(vv->vs[1]==v) set_toggle(vv);
    if(vv->vs[0]==v){
      Node* nv=compress(ee,vv);
      ee->p=nv;
      pushup(ee);
      vv->p=nv;
      pushup(vv);pushup(nv);
      ll=nv;
    }else{
      Node* nv=vv;
      Node* ch=nv->ch[0];
      propagate(ch);
      nv->ch[0]=ee;
      ee->p=nv;
      pushup(ee);

      Node* bt=nv->q;
      Node* rk=nullptr;
      if(bt){
        propagate(bt);
        rk=rake(bt,ch);
        bt->p=rk;
        ch->p=rk;
        pushup(bt);pushup(ch);
      }else{
        rk=ch;
      }
      nv->q=rk;
      rk->p=nv;
      pushup(rk);pushup(nv);
      ll=nv;
    }

    assert(nnu);
    Node* uu=expose(nnu);
    propagate(uu);
    if(uu->vs[0]==u) set_toggle(uu);
    if(uu->vs[1]==u){
      Node* tp=compress(uu,ll);
      uu->p=tp;
      ll->p=tp;
      pushup(uu);pushup(ll);pushup(tp);
    }else{
      Node* nu=uu;
      Node* ch=nu->ch[1];
      toggle(ch);
      propagate(ch);

      nu->ch[1]=ll;
      ll->p=nu;
      pushup(ll);

      Node* al=nu->q;
      Node* rk=nullptr;
      if(al){
        propagate(al);
        rk=rake(al,ch);
        al->p=rk;
        ch->p=rk;
        pushup(al);pushup(ch);
      }else{
        rk=ch;
      }
      nu->q=rk;
      rk->p=nu;
      pushup(rk);pushup(nu);
    }
    return ee;
  }

  void cut(Vertex* u,Vertex *v){
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    Node* rr=rt->ch[1];
    rr->p=nullptr;
    set_toggle(rr);
    dispose_node(rr->ch[1]);
    bring(rr);bring(rt);
  }

  Node* path(Vertex* u,Vertex* v){
    assert(u!=v);
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    propagate(rt->ch[1]);
    return rt->ch[1]->ch[0];
  }

  void set_vertex(Vertex* u,Vertex v){
    auto t=expose(u);
    *u=v;
    pushup(t);
  }

  void set_edge(Vertex* u,Vertex* v,const Cluster &w){
    auto t=path(u,v);
    assert(t->type==Type::Edge);
    t->dat=w;
    while(t) pushup(t),t=t->p;
  }

  Cluster get_path(Vertex* u,Vertex* v){
    return path(u,v)->dat;
  }

  Cluster get_subtree(Vertex* v){
    return expose(v)->dat;
  }

  // subtree of v when p is root
  Cluster get_subtree(Vertex* p,Vertex* v){
    Node* t=path(p,v);
    Cluster res=t->p->ch[1]->dat;
    res.toggle();
    Node* rk=t->p->q;
    if(t->p->q){
      assert(rk->vs[1]==t->p->ch[1]->vs[0]);
      res=Cluster::rake(res,rk->dat);
    }
    return res;
  }
};

#undef call_from_test

using ll = long long;
struct Vertex{
  void* handle;
  ll val;
  Vertex(ll val=0):handle(nullptr),val(val){}
};

struct Cluster{
  ll sm,md,chd,ma;
  Cluster():sm(0),md(0),chd(0),ma(0){}
  void toggle(){}
  static Cluster compress(Cluster x,Vertex *v,Cluster y){
    Cluster z;
    z.sm=x.sm+(v->val)+y.sm;
    z.md=max({x.md,x.chd,y.md});
    z.ma=x.sm+(v->val)+y.sm;
    return z;
  }
  static Cluster rake(Cluster x,Cluster y){
    x.sm+=y.sm;
    x.chd=max({x.chd,y.chd,y.ma});
    return x;
  }
};

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  const char newl = '\n';

  int n;
  cin>>n;
  vector<int> ws(n);
  for(int i=0;i<n;i++) cin>>ws[i];

  const size_t LIM = 1e5;
  TopTree<Vertex, Cluster, LIM> G;

  vector<Vertex*> vs(n);
  for(int i=0;i<n;i++) vs[i]=G.create(Vertex(ws[i]));

  for(int i=1;i<n;i++){
    int u,v;
    cin>>u>>v;
    u--;v--;
    G.link(vs[u],Cluster(),vs[v]);
  }

  int q;
  cin>>q;
  for(int i=0;i<q;i++){
    int a,b;
    cin>>a>>b;
    a--;b--;
    ll res=G.get_path(vs[a],vs[b]).md;
    auto ab=G.get_subtree(vs[a],vs[b]);
    auto ba=G.get_subtree(vs[b],vs[a]);
    chmax(res,max(ab.chd,ab.ma));
    chmax(res,max(ba.chd,ba.ma));
    cout<<res<<newl;
  }
  return 0;
}
accuracy: 1
time_ms: 330
memory_kb: 43228
final_rank: 10

code_snippet: #define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=3037"

#include<bits/stdc++.h>
using namespace std;

#define call_from_test

#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif


#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename Vertex, typename Cluster, size_t LIM>
struct TopTree{
  enum Type { Compress, Rake, Edge };
  struct Node{
    Vertex* vs[2];
    Cluster dat;
    Node* p;
    Node* q;
    Node* ch[2];
    bool rev,guard;
    Type type;
    Node():p(nullptr),q(nullptr),rev(false),guard(false){}
  };

  static array<Vertex, LIM> pool_v;
  static array<Node, LIM> pool_c;
  size_t ptr_v,ptr_c;

  Cluster id;
  TopTree(Cluster id=Cluster()):ptr_v(0),ptr_c(0),id(id){}

  inline Vertex* create(Vertex v=Vertex()){
    auto t=&pool_v[ptr_v++];
    auto dummy=&pool_v[ptr_v++];
    *t=v;
    link(t,id,dummy);
    return t;
  }

  inline Node* edge(Vertex* u,Cluster w,Vertex* v){
    auto t=&(pool_c[ptr_c++]);
    t->vs[0]=u;t->vs[1]=v;t->dat=w;t->type=Type::Edge;
    return pushup(t);
  }

  inline Node* compress(Node* l,Node* r){
    auto t=&(pool_c[ptr_c++]);
    t->ch[0]=l;t->ch[1]=r;t->type=Type::Compress;
    return pushup(t);
  }

  inline Node* rake(Node* l,Node* r){
    auto t=&(pool_c[ptr_c++]);
    t->ch[0]=l;t->ch[1]=r;t->type=Type::Rake;
    return pushup(t);
  }

  int parent_dir(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->guard) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  int parent_dir_ignore_guard(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  inline Node* pushup(Node* const t){
    Node* const l=t->ch[0];
    Node* const r=t->ch[1];

    if(t->type==Type::Compress){
      assert(l->vs[1]==r->vs[0]);
      t->vs[0]=l->vs[0];
      t->vs[1]=r->vs[1];

      Cluster lf=l->dat;
      if(t->q){
        assert(l->vs[1]==t->q->vs[1]);
        lf=Cluster::rake(l->dat,t->q->dat);
      }
      t->dat=Cluster::compress(lf,r->vs[0],r->dat);

      l->vs[1]->handle=t;
    }

    if(t->type==Type::Rake){
      propagate(t);
      assert(l->vs[1]==r->vs[1]);
      t->vs[0]=l->vs[0];
      t->vs[1]=l->vs[1];
      t->dat=Cluster::rake(l->dat,r->dat);
    }else{
      if(!t->p){
        t->vs[0]->handle=t;
        t->vs[1]->handle=t;
      }else if(t->p->type==Type::Compress){
        if(parent_dir(t)==-1)
          t->vs[0]->handle=t;
      }else if(t->p->type==Type::Rake){
        t->vs[0]->handle=t;
      }
    }
    return t;
  }

  inline void toggle(Node* t){
    if(t->type==Type::Edge){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
    }else if(t->type==Type::Compress){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
      t->rev^=true;
    }else if(t->type==Type::Rake){
    }else abort();
  }

  inline void propagate(Node* t){
    if(t->type==Type::Compress){
      if(t->rev){
        assert(t->ch[0] and t->ch[1]);
        swap(t->ch[0],t->ch[1]);
        toggle(t->ch[0]);
        toggle(t->ch[1]);
        t->rev=false;
      }
    }
  }

  void set_toggle(Node* v){
    toggle(v);propagate(v);
  }

  void pushdown(Node* t){
    if(!t) return;
    pushdown(t->p);
    propagate(t);
  }

  void rotate(Node* t,Node* x,size_t dir){
    Node* y=x->p;
    int par=parent_dir_ignore_guard(x);
    propagate(t->ch[dir]);
    x->ch[dir^1]=t->ch[dir];
    t->ch[dir]->p=x;
    t->ch[dir]=x;
    x->p=t;
    t->p=y;
    if(~par) y->ch[par]=t;
    else if(y and y->type==Type::Compress) y->q=t;
    pushup(x);pushup(t);
    if(y and !y->guard) pushup(y);
  }

  void splay(Node* t){
    assert(t->type!=Type::Edge);
    propagate(t);

    while(~parent_dir(t)){
      Node* q=t->p;
      if(q->type!=t->type) break;
      if(~parent_dir(q) and q->p and q->p->type==q->type){
        Node* r=q->p;
        if(r->p) propagate(r->p);
        propagate(r);propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        int rq_dir=parent_dir(q);
        if(rq_dir==qt_dir){
          rotate(q,r,rq_dir^1);
          rotate(t,q,qt_dir^1);
        }else{
          rotate(t,q,qt_dir^1);
          rotate(t,r,rq_dir^1);
        }
      }else{
        if(q->p) propagate(q->p);
        propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        rotate(t,q,qt_dir^1);
      }
    }
  }

  Node* expose(Node* t){
    pushdown(t);
    while(true){
      assert(t->type!=Type::Rake);
      if(t->type==Type::Compress) splay(t);
      Node* n=nullptr;
      {
        Node* p=t->p;
        if(!p) break;
        if(p->type==Type::Rake){
          propagate(p);
          splay(p);
          n=p->p;
        }
        if(p->type==Type::Compress){
          propagate(p);
          if(p->guard and ~parent_dir_ignore_guard(t)) break;
          n=p;
        }
      }
      splay(n);
      int dir=parent_dir_ignore_guard(n);
      if(dir==-1 or n->p->type==Type::Rake) dir=0;

      Node* const c=n->ch[dir];
      if(dir==1){
        set_toggle(c);
        set_toggle(t);
      }
      int n_dir=parent_dir(t);
      if(~n_dir){
        Node* const r=t->p;
        propagate(c);
        propagate(r);
        r->ch[n_dir]=c;
        c->p=r;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(r);pushup(t);pushup(n);
        splay(r);
      }else{
        propagate(c);
        n->q=c;
        c->p=n;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(t);pushup(n);
      }
      if(t->type==Type::Edge) t=n;
    }
    return t;
  }

  Node* expose(Vertex* v){
    return expose((Node*)(v->handle));
  }

  void soft_expose(Vertex* u,Vertex* v){
    pushdown((Node*)u->handle);
    pushdown((Node*)v->handle);
    Node* rt=expose(u);

    if(u->handle==v->handle){
      if(rt->vs[1]==u or rt->vs[0]==v)
        set_toggle(rt);
      return;
    }

    rt->guard=true;
    Node* soft=expose(v);
    rt->guard=false;

    pushup(rt);
    if(parent_dir(soft)==0) set_toggle(rt);
  }

  void bring(Node* rt){
    Node* rk=rt->q;
    if(!rk){
      Node* ll=rt->ch[0];
      ll->p=nullptr;
      pushup(ll);
    }else if(rk->type==Type::Compress or rk->type==Type::Edge){
      propagate(rk);

      Node* nr=rk;
      set_toggle(nr);
      rt->ch[1]=nr;
      nr->p=rt;
      rt->q=nullptr;

      pushup(nr);pushup(rt);
    }else if(rk->type==Type::Rake){
      propagate(rk);
      while(rk->ch[1]->type==Type::Rake){
        propagate(rk->ch[1]);
        rk=rk->ch[1];
      }
      pushdown(rk);

      rt->guard=true;
      splay(rk);
      rt->guard=false;

      Node* ll=rk->ch[0];
      Node* rr=rk->ch[1];
      propagate(ll);
      set_toggle(rr);

      rt->ch[1]=rr;
      rr->p=rt;

      rt->q=ll;
      ll->p=rt;

      pushup(ll);pushup(rr);pushup(rt);
    }
  }

  Node* link(Vertex* u,Cluster w,Vertex* v){
    if(!u->handle and !v->handle) return edge(u,w,v);

    Node* nnu=(Node*)u->handle;
    Node* nnv=(Node*)v->handle;
    Node* ee=edge(u,w,v);
    Node* ll=nullptr;

    if(!nnv) ll=ee;
    else{
      Node* vv=expose(nnv);
      propagate(vv);
      if(vv->vs[1]==v) set_toggle(vv);
      if(vv->vs[0]==v){
        Node* nv=compress(ee,vv);
        ee->p=nv;
        pushup(ee);
        vv->p=nv;
        pushup(vv);pushup(nv);
        ll=nv;
      }else{
        Node* nv=vv;
        Node* ch=nv->ch[0];
        propagate(ch);
        nv->ch[0]=ee;
        ee->p=nv;
        pushup(ee);

        Node* bt=nv->q;
        Node* rk=nullptr;
        if(bt){
          propagate(bt);
          rk=rake(bt,ch);
          bt->p=rk;
          ch->p=rk;
          pushup(bt);pushup(ch);
        }else{
          rk=ch;
        }
        nv->q=rk;
        rk->p=nv;
        pushup(rk);pushup(nv);
        ll=nv;
      }
    }

    if(nnu){
      Node* uu=expose(nnu);
      propagate(uu);
      if(uu->vs[0]==u) set_toggle(uu);
      if(uu->vs[1]==u){
        Node* tp=compress(uu,ll);
        uu->p=tp;
        ll->p=tp;
        pushup(uu);pushup(ll);pushup(tp);
      }else{
        Node* nu=uu;
        Node* ch=nu->ch[1];
        toggle(ch);
        propagate(ch);

        nu->ch[1]=ll;
        ll->p=nu;
        pushup(ll);

        Node* al=nu->q;
        Node* rk=nullptr;
        if(al){
          propagate(al);
          rk=rake(al,ch);
          al->p=rk;
          ch->p=rk;
          pushup(al);pushup(ch);
        }else{
          rk=ch;
        }
        nu->q=rk;
        rk->p=nu;
        pushup(rk);pushup(nu);
      }
    }
    return ee;
  }

  void cut(Vertex* u,Vertex *v){
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    Node* rr=rt->ch[1];
    rr->p=nullptr;
    set_toggle(rr);
    bring(rr);bring(rt);
  }

  Node* path(Vertex* u,Vertex* v){
    assert(u!=v);
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    propagate(rt->ch[1]);
    return rt->ch[1]->ch[0];
  }

  void set_vertex(Vertex* u,Vertex v){
    auto t=expose(u);
    *u=v;
    pushup(t);
  }

  void set_edge(Vertex* u,Vertex* v,const Cluster &w){
    auto t=path(u,v);
    assert(t->type==Type::Edge);
    t->dat=w;
    while(t) pushup(t),t=t->p;
  }

  Cluster get_path(Vertex* u,Vertex* v){
    return path(u,v)->dat;
  }

  Cluster get_subtree(Vertex* v){
    return expose(v)->dat;
  }

  // subtree of v when p is root
  Cluster get_subtree(Vertex* p,Vertex* v){
    Node* t=path(p,v);
    Cluster res=t->p->ch[1]->dat;
    res.toggle();
    Node* rk=t->p->q;
    if(t->p->q){
      assert(rk->vs[1]==t->p->ch[1]->vs[0]);
      res=Cluster::rake(res,rk->dat);
    }
    return res;
  }
};
template<typename Vertex, typename Cluster, size_t LIM>
array<Vertex, LIM> TopTree<Vertex, Cluster, LIM>::pool_v;
template<typename Vertex, typename Cluster, size_t LIM>
array<typename TopTree<Vertex, Cluster, LIM>::Node, LIM>
TopTree<Vertex, Cluster, LIM>::pool_c;
//END CUT HERE
#ifndef call_from_test
//INSERT ABOVE HERE
signed main(){
  return 0;
}
#endif

#undef call_from_test

using ll = long long;
struct Vertex{
  void* handle;
  ll val;
  Vertex(ll val=0):handle(nullptr),val(val){}
};

struct Cluster{
  ll sm,md,chd,ma;
  Cluster():sm(0),md(0),chd(0),ma(0){}
  void toggle(){}
  static Cluster compress(Cluster x,Vertex *v,Cluster y){
    Cluster z;
    z.sm=x.sm+(v->val)+y.sm;
    z.md=max({x.md,x.chd,y.md});
    z.ma=x.sm+(v->val)+y.sm;
    return z;
  }
  static Cluster rake(Cluster x,Cluster y){
    x.sm+=y.sm;
    x.chd=max({x.chd,y.chd,y.ma});
    return x;
  }
};

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  const char newl = '\n';

  int n;
  cin>>n;
  vector<int> ws(n);
  for(int i=0;i<n;i++) cin>>ws[i];

  const size_t LIM = 1e6;
  TopTree<Vertex, Cluster, LIM> G;

  vector<Vertex*> vs(n);
  for(int i=0;i<n;i++) vs[i]=G.create(Vertex(ws[i]));

  for(int i=1;i<n;i++){
    int u,v;
    cin>>u>>v;
    u--;v--;
    G.link(vs[u],Cluster(),vs[v]);
  }

  int q;
  cin>>q;
  for(int i=0;i<q;i++){
    int a,b;
    cin>>a>>b;
    a--;b--;
    ll res=G.get_path(vs[a],vs[b]).md;
    auto ab=G.get_subtree(vs[a],vs[b]);
    auto ba=G.get_subtree(vs[b],vs[a]);
    chmax(res,max(ab.chd,ab.ma));
    chmax(res,max(ba.chd,ba.ma));
    cout<<res<<newl;
  }
  return 0;
}
accuracy: 1
time_ms: 490
memory_kb: 106520
final_rank: 18

code_snippet: #define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=3037"

#include<bits/stdc++.h>
using namespace std;

#define call_from_test

#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif


#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename Vertex, typename Cluster, size_t LIM>
struct TopTree{
  enum Type { Compress, Rake, Edge };
  struct Node{
    Vertex* vs[2];
    Cluster dat;
    Node* p;
    Node* q;
    Node* ch[2];
    bool rev,guard;
    Type type;
    Node():p(nullptr),q(nullptr),rev(false),guard(false){}
  };

  static array<Vertex, LIM> pool_v;
  static array<Node, LIM> pool_c;
  size_t ptr_v,ptr_c;

  Cluster id;
  TopTree(Cluster id=Cluster()):ptr_v(0),ptr_c(0),id(id){}

  inline Vertex* create(Vertex v=Vertex()){
    auto t=&pool_v[ptr_v++];
    auto dummy=&pool_v[ptr_v++];
    *t=v;
    link(t,id,dummy);
    return t;
  }

  inline Node* edge(Vertex* u,Cluster w,Vertex* v){
    auto t=&(pool_c[ptr_c++]);
    t->vs[0]=u;t->vs[1]=v;t->dat=w;t->type=Type::Edge;
    return pushup(t);
  }

  inline Node* compress(Node* l,Node* r){
    auto t=&(pool_c[ptr_c++]);
    t->ch[0]=l;t->ch[1]=r;t->type=Type::Compress;
    return pushup(t);
  }

  inline Node* rake(Node* l,Node* r){
    auto t=&(pool_c[ptr_c++]);
    t->ch[0]=l;t->ch[1]=r;t->type=Type::Rake;
    return pushup(t);
  }

  int parent_dir(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->guard) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  int parent_dir_ignore_guard(Node* t){
    Node* p=t->p;
    if(!p) return -1;
    if(p->ch[0]==t) return 0;
    if(p->ch[1]==t) return 1;
    return -1;
  }

  inline Node* pushup(Node* const t){
    Node* const l=t->ch[0];
    Node* const r=t->ch[1];

    if(t->type==Type::Compress){
      assert(l->vs[1]==r->vs[0]);
      t->vs[0]=l->vs[0];
      t->vs[1]=r->vs[1];

      Cluster lf=l->dat;
      if(t->q){
        assert(l->vs[1]==t->q->vs[1]);
        lf=Cluster::rake(l->dat,t->q->dat);
      }
      t->dat=Cluster::compress(lf,r->vs[0],r->dat);

      l->vs[1]->handle=t;
    }

    if(t->type==Type::Rake){
      propagate(t);
      assert(l->vs[1]==r->vs[1]);
      t->vs[0]=l->vs[0];
      t->vs[1]=l->vs[1];
      t->dat=Cluster::rake(l->dat,r->dat);
    }else{
      if(!t->p){
        t->vs[0]->handle=t;
        t->vs[1]->handle=t;
      }else if(t->p->type==Type::Compress){
        if(parent_dir(t)==-1)
          t->vs[0]->handle=t;
      }else if(t->p->type==Type::Rake){
        t->vs[0]->handle=t;
      }
    }
    return t;
  }

  inline void toggle(Node* t){
    if(t->type==Type::Edge){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
    }else if(t->type==Type::Compress){
      swap(t->vs[0],t->vs[1]);
      t->dat.toggle();
      t->rev^=true;
    }else if(t->type==Type::Rake){
    }else abort();
  }

  inline void propagate(Node* t){
    if(t->type==Type::Compress){
      if(t->rev){
        assert(t->ch[0] and t->ch[1]);
        swap(t->ch[0],t->ch[1]);
        toggle(t->ch[0]);
        toggle(t->ch[1]);
        t->rev=false;
      }
    }
  }

  void set_toggle(Node* v){
    toggle(v);propagate(v);
  }

  void pushdown(Node* t){
    if(!t) return;
    pushdown(t->p);
    propagate(t);
  }

  void rotate(Node* t,Node* x,size_t dir){
    Node* y=x->p;
    int par=parent_dir_ignore_guard(x);
    propagate(t->ch[dir]);
    x->ch[dir^1]=t->ch[dir];
    t->ch[dir]->p=x;
    t->ch[dir]=x;
    x->p=t;
    t->p=y;
    if(~par) y->ch[par]=t;
    else if(y and y->type==Type::Compress) y->q=t;
    pushup(x);pushup(t);
    if(y and !y->guard) pushup(y);
  }

  void splay(Node* t){
    assert(t->type!=Type::Edge);
    propagate(t);

    while(~parent_dir(t)){
      Node* q=t->p;
      if(q->type!=t->type) break;
      if(~parent_dir(q) and q->p and q->p->type==q->type){
        Node* r=q->p;
        if(r->p) propagate(r->p);
        propagate(r);propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        int rq_dir=parent_dir(q);
        if(rq_dir==qt_dir){
          rotate(q,r,rq_dir^1);
          rotate(t,q,qt_dir^1);
        }else{
          rotate(t,q,qt_dir^1);
          rotate(t,r,rq_dir^1);
        }
      }else{
        if(q->p) propagate(q->p);
        propagate(q);propagate(t);
        int qt_dir=parent_dir(t);
        rotate(t,q,qt_dir^1);
      }
    }
  }

  Node* expose(Node* t){
    pushdown(t);
    while(true){
      assert(t->type!=Type::Rake);
      if(t->type==Type::Compress) splay(t);
      Node* n=nullptr;
      {
        Node* p=t->p;
        if(!p) break;
        if(p->type==Type::Rake){
          propagate(p);
          splay(p);
          n=p->p;
        }
        if(p->type==Type::Compress){
          propagate(p);
          if(p->guard and ~parent_dir_ignore_guard(t)) break;
          n=p;
        }
      }
      splay(n);
      int dir=parent_dir_ignore_guard(n);
      if(dir==-1 or n->p->type==Type::Rake) dir=0;

      Node* const c=n->ch[dir];
      if(dir==1){
        set_toggle(c);
        set_toggle(t);
      }
      int n_dir=parent_dir(t);
      if(~n_dir){
        Node* const r=t->p;
        propagate(c);
        propagate(r);
        r->ch[n_dir]=c;
        c->p=r;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(r);pushup(t);pushup(n);
        splay(r);
      }else{
        propagate(c);
        n->q=c;
        c->p=n;
        n->ch[dir]=t;
        t->p=n;
        pushup(c);pushup(t);pushup(n);
      }
      if(t->type==Type::Edge) t=n;
    }
    return t;
  }

  Node* expose(Vertex* v){
    return expose((Node*)(v->handle));
  }

  void soft_expose(Vertex* u,Vertex* v){
    pushdown((Node*)u->handle);
    pushdown((Node*)v->handle);
    Node* rt=expose(u);

    if(u->handle==v->handle){
      if(rt->vs[1]==u or rt->vs[0]==v)
        set_toggle(rt);
      return;
    }

    rt->guard=true;
    Node* soft=expose(v);
    rt->guard=false;

    pushup(rt);
    if(parent_dir(soft)==0) set_toggle(rt);
  }

  void bring(Node* rt){
    Node* rk=rt->q;
    if(!rk){
      Node* ll=rt->ch[0];
      ll->p=nullptr;
      pushup(ll);
    }else if(rk->type==Type::Compress or rk->type==Type::Edge){
      propagate(rk);

      Node* nr=rk;
      set_toggle(nr);
      rt->ch[1]=nr;
      nr->p=rt;
      rt->q=nullptr;

      pushup(nr);pushup(rt);
    }else if(rk->type==Type::Rake){
      propagate(rk);
      while(rk->ch[1]->type==Type::Rake){
        propagate(rk->ch[1]);
        rk=rk->ch[1];
      }
      pushdown(rk);

      rt->guard=true;
      splay(rk);
      rt->guard=false;

      Node* ll=rk->ch[0];
      Node* rr=rk->ch[1];
      propagate(ll);
      set_toggle(rr);

      rt->ch[1]=rr;
      rr->p=rt;

      rt->q=ll;
      ll->p=rt;

      pushup(ll);pushup(rr);pushup(rt);
    }
  }

  Node* link(Vertex* u,Cluster w,Vertex* v){
    if(!u->handle and !v->handle) return edge(u,w,v);

    Node* nnu=(Node*)u->handle;
    Node* nnv=(Node*)v->handle;
    Node* ee=edge(u,w,v);
    Node* ll=nullptr;

    if(!nnv) ll=ee;
    else{
      Node* vv=expose(nnv);
      propagate(vv);
      if(vv->vs[1]==v) set_toggle(vv);
      if(vv->vs[0]==v){
        Node* nv=compress(ee,vv);
        ee->p=nv;
        pushup(ee);
        vv->p=nv;
        pushup(vv);pushup(nv);
        ll=nv;
      }else{
        Node* nv=vv;
        Node* ch=nv->ch[0];
        propagate(ch);
        nv->ch[0]=ee;
        ee->p=nv;
        pushup(ee);

        Node* bt=nv->q;
        Node* rk=nullptr;
        if(bt){
          propagate(bt);
          rk=rake(bt,ch);
          bt->p=rk;
          ch->p=rk;
          pushup(bt);pushup(ch);
        }else{
          rk=ch;
        }
        nv->q=rk;
        rk->p=nv;
        pushup(rk);pushup(nv);
        ll=nv;
      }
    }

    if(nnu){
      Node* uu=expose(nnu);
      propagate(uu);
      if(uu->vs[0]==u) set_toggle(uu);
      if(uu->vs[1]==u){
        Node* tp=compress(uu,ll);
        uu->p=tp;
        ll->p=tp;
        pushup(uu);pushup(ll);pushup(tp);
      }else{
        Node* nu=uu;
        Node* ch=nu->ch[1];
        toggle(ch);
        propagate(ch);

        nu->ch[1]=ll;
        ll->p=nu;
        pushup(ll);

        Node* al=nu->q;
        Node* rk=nullptr;
        if(al){
          propagate(al);
          rk=rake(al,ch);
          al->p=rk;
          ch->p=rk;
          pushup(al);pushup(ch);
        }else{
          rk=ch;
        }
        nu->q=rk;
        rk->p=nu;
        pushup(rk);pushup(nu);
      }
    }
    return ee;
  }

  void cut(Vertex* u,Vertex *v){
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    Node* rr=rt->ch[1];
    rr->p=nullptr;
    set_toggle(rr);
    bring(rr);bring(rt);
  }

  Node* path(Vertex* u,Vertex* v){
    assert(u!=v);
    soft_expose(u,v);
    Node* rt=(Node*)u->handle;
    propagate(rt);
    propagate(rt->ch[1]);
    return rt->ch[1]->ch[0];
  }

  void set_vertex(Vertex* u,Vertex v){
    auto t=expose(u);
    *u=v;
    pushup(t);
  }

  void set_edge(Vertex* u,Vertex* v,const Cluster &w){
    auto t=path(u,v);
    assert(t->type==Type::Edge);
    t->dat=w;
    while(t) pushup(t),t=t->p;
  }

  Cluster get_path(Vertex* u,Vertex* v){
    return path(u,v)->dat;
  }

  Cluster get_subtree(Vertex* v){
    return expose(v)->dat;
  }

  // subtree of v when p is root
  Cluster get_subtree(Vertex* p,Vertex* v){
    Node* t=path(p,v);
    Cluster res=t->p->ch[1]->dat;
    res.toggle();
    Node* rk=t->p->q;
    if(t->p->q){
      assert(rk->vs[1]==t->p->ch[1]->vs[0]);
      res=Cluster::rake(res,rk->dat);
    }
    return res;
  }
};
template<typename Vertex, typename Cluster, size_t LIM>
array<Vertex, LIM> TopTree<Vertex, Cluster, LIM>::pool_v;
template<typename Vertex, typename Cluster, size_t LIM>
array<typename TopTree<Vertex, Cluster, LIM>::Node, LIM>
TopTree<Vertex, Cluster, LIM>::pool_c;
//END CUT HERE
#ifndef call_from_test
//INSERT ABOVE HERE
signed main(){
  return 0;
}
#endif

#undef call_from_test

using ll = long long;
struct Vertex{
  void* handle;
  ll val;
  Vertex(ll val=0):handle(nullptr),val(val){}
};

struct Cluster{
  ll sm,md,chd,ma;
  Cluster():sm(0),md(0),chd(0),ma(0){}
  void toggle(){}
  static Cluster compress(Cluster x,Vertex *v,Cluster y){
    Cluster z;
    z.sm=x.sm+(v->val)+y.sm;
    z.md=max({x.md,x.chd,y.md});
    z.ma=x.sm+(v->val)+y.sm;
    return z;
  }
  static Cluster rake(Cluster x,Cluster y){
    x.sm+=y.sm;
    x.chd=max({x.chd,y.chd,y.ma});
    return x;
  }
};

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  const char newl = '\n';

  int n;
  cin>>n;
  vector<int> ws(n);
  for(int i=0;i<n;i++) cin>>ws[i];

  const size_t LIM = 1e6;
  TopTree<Vertex, Cluster, LIM> G;

  vector<Vertex*> vs(n);
  for(int i=0;i<n;i++) vs[i]=G.create(Vertex(ws[i]));

  for(int i=1;i<n;i++){
    int u,v;
    cin>>u>>v;
    u--;v--;
    G.link(vs[u],Cluster(),vs[v]);
  }

  const int DEBUG = 0;
  int q;
  cin>>q;
  for(int i=0;i<q;i++){
    int a,b;
    cin>>a>>b;
    a--;b--;
    if(a==b){
      if(DEBUG){
        cout<<"sm:"<<G.get_subtree(vs[a]).sm<<endl;
        cout<<"md:"<<G.get_subtree(vs[a]).md<<endl;
        cout<<"ma:"<<G.get_subtree(vs[a]).ma<<endl;
      }
      cout<<G.get_subtree(vs[a]).md<<newl;
    }else{
      ll res=G.get_path(vs[a],vs[b]).md;
      chmax(res,G.get_subtree(vs[a],vs[b]).ma);
      chmax(res,G.get_subtree(vs[b],vs[a]).ma);

      if(DEBUG){
        cout<<"md:"<<G.get_path(vs[a],vs[b]).md<<endl;
        cout<<"ab:"<<G.get_subtree(vs[a],vs[b]).ma<<endl;
        cout<<"ba:"<<G.get_subtree(vs[b],vs[a]).ma<<endl;
      }
      cout<<res<<newl;
    }
  }
  return 0;
}
accuracy: 0.06382978723404255
time_ms: 20
memory_kb: 104748
final_rank: 20

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
const Int DEBUG = 0;

struct HLDecomposition {
  Int n,pos;
  vector<vector<Int> > G;
  vector<Int> vid, head, sub, hvy, par, dep, inv, type;
  
  HLDecomposition(){}
  HLDecomposition(Int sz):
    n(sz),pos(0),G(n),
    vid(n,-1),head(n),sub(n,1),hvy(n,-1),
    par(n),dep(n),inv(n),type(n){}
  
  void add_edge(Int u, Int v) {
    G[u].push_back(v);
    G[v].push_back(u);
  }

  void build(vector<Int> rs={0}) {
    Int c=0;
    for(Int r:rs){
      dfs(r);
      bfs(r, c++);
    }
  }
  
  void dfs(Int rt) {
    using T = pair<Int, Int>;
    stack<T> st;
    par[rt]=-1;
    dep[rt]=0;
    st.emplace(rt,0);
    while(!st.empty()){
      Int v=st.top().first;
      Int &i=st.top().second;
      if(i<(Int)G[v].size()){
	Int u=G[v][i++];
	if(u==par[v]) continue;
	par[u]=v;
	dep[u]=dep[v]+1;
	st.emplace(u,0);
      }else{
	st.pop();
	Int res=0;
	for(Int u:G[v]){
	  if(u==par[v]) continue;
	  sub[v]+=sub[u];
	  if(res<sub[u]) res=sub[u],hvy[v]=u;
	}
      }
    }
  }

  void bfs(Int r,Int c) {
    Int &k=pos;
    queue<Int> q({r});
    while(!q.empty()){
      Int h=q.front();q.pop();
      for(Int i=h;i!=-1;i=hvy[i]) {
	type[i]=c;
	vid[i]=k++;
	inv[vid[i]]=i;
	head[i]=h;
	for(Int j:G[i])
	  if(j!=par[i]&&j!=hvy[i]) q.push(j);
      }
    }
  }
  
  // for_each(vertex)
  // [l,r] <- attention!!
  void for_each(Int u, Int v, const function<void(Int, Int)>& f) {
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      f(max(vid[head[v]],vid[u]),vid[v]);
      if(head[u]!=head[v]) v=par[head[v]];
      else break;
    }
  }
  
  // for_each(edge)
  // [l,r] <- attention!!
  void for_each_edge(Int u, Int v, const function<void(Int, Int)>& f) {
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      if(head[u]!=head[v]){
	f(vid[head[v]],vid[v]);
        v=par[head[v]];
      } else{
	if(u!=v) f(vid[u]+1,vid[v]);
	break;
      }
    }
  }

  Int lca(Int u,Int v){
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      if(head[u]==head[v]) return u;
      v=par[head[v]];
    }
  }

  Int distance(Int u,Int v){
    return dep[u]+dep[v]-2*dep[lca(u,v)];
  }
};


template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}


template <typename T,typename E>
struct SegmentTree{
  typedef function<T(T,T)> F;
  typedef function<T(T,E)> G;
  Int n;
  F f;
  G g;
  T d1;
  E d0;
  vector<T> dat;
  SegmentTree(){};
  SegmentTree(Int n_,F f,G g,T d1,
	      vector<T> v=vector<T>()):
    f(f),g(g),d1(d1){
    init(n_);
    if(n_==(Int)v.size()) build(n_,v);
  }
  void init(Int n_){
    n=1;
    while(n<n_) n*=2;
    dat.clear();
    dat.resize(2*n-1,d1);
  }
  void build(Int n_, vector<T> v){
    for(Int i=0;i<n_;i++) dat[i+n-1]=v[i];
    for(Int i=n-2;i>=0;i--)
      dat[i]=f(dat[i*2+1],dat[i*2+2]);
  }
  void update(Int k,E a){
    k+=n-1;
    dat[k]=g(dat[k],a);
    while(k>0){
      k=(k-1)/2;
      dat[k]=f(dat[k*2+1],dat[k*2+2]);
    }
  }
  inline T query(Int a,Int b){
    T vl=d1,vr=d1;
    for(Int l=a+n,r=b+n;l<r;l>>=1,r>>=1) {
      if(l&1) vl=f(vl,dat[(l++)-1]);
      if(r&1) vr=f(dat[(--r)-1],vr);
    }
    return f(vl,vr);
  }

  Int find(Int a,Int b,function<bool(T)> &check,Int k,Int l,Int r){
    if(!check(dat[k])||r<=a||b<=l) return -1;
    if(k>=n-1) return k-(n-1);
    Int m=(l+r)>>1;
    Int vl=find(a,b,check,k*2+1,l,m);
    if(~vl) return vl;
    return find(a,b,check,k*2+2,m,r);
  }
  
  Int find(Int a,Int b,function<bool(T)> &check){
    return find(a,b,check,0,0,n);
  }
  
};

//INSERT ABOVE HERE
signed main(){
  Int n;
  cin>>n;
  vector<Int> w(n);
  for(Int i=0;i<n;i++) cin>>w[i];
  HLDecomposition hld(n);
  for(Int i=1;i<n;i++){
    Int u,v;
    cin>>u>>v;
    u--;v--;
    hld.add_edge(u,v);
  }
  hld.build();
  auto G=hld.G;
  auto head=hld.head;
  auto vid=hld.vid;
  auto inv=hld.inv;
  
  vector<Int> dp(n),dp2(n,-1),dp3(n,-1);
  using P = pair<Int, Int>;
  vector<set<P> > ps(n);
  function<Int(Int,Int)> dfs=[&](Int v,Int p){
    dp[v]=w[v];
    ps[v].emplace(-1,-1);
    for(Int u:G[v]){
      if(u==p) continue;
      Int k=dfs(u,v);
      dp[v]+=k;
      if(head[v]!=head[u]){
	chmax(dp2[v],k);
	ps[v].emplace(k,u);
	if(DEBUG) cout<<v<<"->"<<u<<":"<<k<<endl;
      }else dp3[v]=k;
    }
    return dp[v];
  };
  dfs(0,-1);
  
  SegmentTree<Int, Int>::F f=[](Int a,Int b){return max(a,b);};
  SegmentTree<Int, Int>::G g=[](Int a,Int b){++a;return b;};
  SegmentTree<Int, Int> seg(n,f,g,-1);
  for(Int i=0;i<n;i++) seg.update(vid[i],dp2[i]);
  
  Int sum=accumulate(w.begin(),w.end(),Int(0));
  Int q;
  cin>>q;
  for(Int i=0;i<q;i++){
    Int u,v;
    cin>>u>>v;
    u--;v--;
    Int ans=sum-dp[hld.lca(u,v)];
    set<Int> s;
    hld.for_each(u,v,[&](Int l,Int r){
	if(l+1<r) chmax(ans,seg.query(l+1,r));
	if(DEBUG) cout<<inv[l]<<" "<<inv[r]<<endl;
	s.emplace(inv[l]);
	s.emplace(inv[r]);
	chmax(ans,dp3[inv[r]]);
      });
    if(DEBUG) cout<<ans<<endl;
    for(Int v:s){
      auto latte=--ps[v].end();
      while(s.count(latte->second)) --latte;
      if(DEBUG)  cout<<v<<" "<<latte->second<<":"<<latte->first<<endl;
      chmax(ans,latte->first);
    }
    cout<<ans<<endl;
  }
  
  
  return 0;
}
accuracy: 1
time_ms: 500
memory_kb: 46304
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> P;

#define fi first
#define se second
#define repl(i,a,b) for(ll i=(ll)(a);i<(ll)(b);i++)
#define rep(i,n) repl(i,0,n)
#define all(x) (x).begin(),(x).end()
#define dbg(x) cout<<#x"="<<x<<endl
#define mmax(x,y) (x>y?x:y)
#define mmin(x,y) (x<y?x:y)
#define maxch(x,y) x=mmax(x,y)
#define minch(x,y) x=mmin(x,y)
#define uni(x) x.erase(unique(all(x)),x.end())
#define exist(x,y) (find(all(x),y)!=x.end())
#define bcnt __builtin_popcount

#define INF 1e16
#define mod 1000000007

ll n,q;
ll w[100001];
vector<ll> g[100001];
ll d[100001];
ll p[20][100001];
vector<ll> s[100001];
ll br[20][100001];

void dfs(ll v,ll pre,ll dist){
  p[0][v]=pre;
  d[v]=dist;
  for(ll nv : g[v]){
    if(nv==pre)continue;
    dfs(nv,v,dist+1);
    w[v]+=w[nv];
    if(s[v].size()>=3&&s[v].back()<w[nv]){
      s[v].pop_back();
      s[v].push_back(w[nv]);
      sort(all(s[v]));
      reverse(all(s[v]));
    }else if(s[v].size()<=2){
      s[v].push_back(w[nv]);
      sort(all(s[v]));
      reverse(all(s[v]));
    }
  }
}

int lca(int u,int v){
  if(d[u]>d[v])swap(u,v);
  for(int k=0;k<20;k++){
    if((d[v]-d[u])>>k&1){
      v=p[k][v];
    }
  }
  if(u==v)return u;
  for(int k=20-1;k>=0;k--){
    if(p[k][u]!=p[k][v]){
      u=p[k][u];
      v=p[k][v];
    }
  }
  return p[0][u];
}

int main(){
  cin>>n;
  rep(i,n)cin>>w[i];
  rep(i,n-1){
    ll a,b;
    cin>>a>>b;
    a--;b--;
    g[a].push_back(b);
    g[b].push_back(a);
  }
  dfs(0,-1,0);

  rep(v,n){
    for(ll ch : g[v]){
      if(d[ch]<d[v])continue;
      if(w[ch]==s[v][0]){
        if(s[v].size()>=2)br[0][ch]=s[v][1];
        else br[0][ch]=-INF;
      }else{
        if(s[v].size()>=1)br[0][ch]=s[v][0];
        else br[0][ch]=-INF;
      }
    }
  }

  rep(k,19){
    rep(i,n){
      if(p[k][i]!=-1) p[k+1][i]=p[k][p[k][i]];
      else p[k+1][i]=-1;
    }
  }

  rep(k,19){
    rep(i,n){
      if(p[k][i]!=-1) br[k+1][i]=max(br[k][i],br[k][p[k][i]]);
      else br[k+1][i]=-INF;
    }
  }

  cin>>q;
  while(q--){
    ll a,b;
    cin>>a>>b;
    a--;b--;
    if(d[a]>d[b])swap(a,b);
    ll lc=lca(a,b);
    ll res=w[0]-w[lc];

    if(lc==a){
      ll nb=b,pb=b;
      while(p[0][pb]!=lc&&pb!=lc){
        ll i=0;
        while(p[i][pb]!=-1&&d[p[i][pb]]>d[lc])i++;
        i--;
        pb=p[i][pb];
      }
      while(nb!=lc){
        ll i=0;
        while(p[i][nb]!=-1&&d[p[i][nb]]>=d[lc])i++;
        i--;
        maxch(res,br[i][nb]);
        nb=p[i][nb];
      }

      if(s[b].size()>0)maxch(res,s[b][0]);

      multiset<ll> rest;
      rep(k,s[a].size())rest.insert(s[a][k]);
      if(rest.find(w[pb])!=rest.end())rest.erase(rest.find(w[pb]));
      if(rest.size()>0)maxch(res,*rest.rbegin());
    }else{
      ll na=a,pa=a;
      while(p[0][pa]!=lc){
        ll i=0;
        while(p[i][pa]!=-1&&d[p[i][pa]]>d[lc])i++;
        i--;
        pa=p[i][pa];
      }
      while(na!=pa){
        ll i=0;
        while(p[i][na]!=-1&&d[p[i][na]]>=d[pa])i++;
        i--;
        maxch(res,br[i][na]);
        na=p[i][na];
      }

      ll nb=b,pb=b;
      while(p[0][pb]!=lc){
        ll i=0;
        while(p[i][pb]!=-1&&d[p[i][pb]]>d[lc])i++;
        i--;
        pb=p[i][pb];
      }
      while(nb!=pb){
        ll i=0;
        while(p[i][nb]!=-1&&d[p[i][nb]]>=d[pb])i++;
        i--;
        maxch(res,br[i][nb]);
        nb=p[i][nb];
      }

      if(s[a].size()>0)maxch(res,s[a][0]);
      if(s[b].size()>0)maxch(res,s[b][0]);
      multiset<ll> rest;
      rep(k,s[lc].size())rest.insert(s[lc][k]);
      if(rest.find(w[pa])!=rest.end())rest.erase(rest.find(w[pa]));
      if(rest.find(w[pb])!=rest.end())rest.erase(rest.find(w[pb]));
      if(rest.size()>0)maxch(res,*rest.rbegin());
    }
    cout<<res<<endl;
  }

  return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 46092
final_rank: 9

code_snippet: #include <bits/stdc++.h>
#define REP(i, a, n) for(ll i = ((ll) a); i < ((ll) n); i++)
using namespace std;
typedef long long ll;

ll N, Q;
ll W[100000], U[100000], V[100000], A[100000], B[100000];
vector<ll> E[100000];
ll x[100000][3], y[100000];
ll depth[100000], parent[20][100000], mx[20][100000];

void dfs(ll v, ll p, ll d) {
  parent[0][v] = p;
  depth[v] = d;
  for(ll u : E[v]) if(u != p) dfs(u, v, d + 1);
}

ll subtree_size(ll v, ll p) {
  vector<ll> child;
  for(ll u : E[v]) if(u != p) child.push_back(subtree_size(u, v));
  sort(child.begin(), child.end(), greater<ll>());
  REP(i, 0, 3) x[v][i] = i < child.size() ? child[i] : 0;
  for(ll u : E[v]) if(u != p) mx[0][u] = x[v][0] != y[u] ? x[v][0] : x[v][1];
  y[v] = W[v];
  REP(i, 0, child.size()) y[v] += child[i];
  return y[v];
}

ll query(ll u, ll v) {
  if(depth[u] > depth[v]) swap(u, v);
  REP(i, 0, 20) if(((depth[v] - depth[u]) >> i) & 1) v = parent[i][v];
  if(u == v) return u;
  for(ll i = 19; i >= 0; i--) if(parent[i][u] != parent[i][v]) {
    u = parent[i][u];
    v = parent[i][v];
  }
  return parent[0][u];
}

int main(void) {
  cin >> N;
  REP(i, 0, N) cin >> W[i];
  REP(i, 0, N - 1) {
    cin >> U[i] >> V[i]; U[i]--; V[i]--;
    E[U[i]].push_back(V[i]);
    E[V[i]].push_back(U[i]);
  }
  cin >> Q;
  REP(i, 0, Q) { cin >> A[i] >> B[i]; A[i]--; B[i]--; }

  dfs(0, -1, 0);
  subtree_size(0, -1);
  REP(i, 0, 19) REP(j, 0, N) parent[i + 1][j] = parent[i][j] >= 0 ? parent[i][parent[i][j]] : -1;
  REP(i, 0, 19) REP(j, 0, N) if(parent[i][j] >= 0) mx[i + 1][j] = max(mx[i][j], mx[i][parent[i][j]]);

  REP(q, 0, Q) {
    ll a = A[q], b = B[q], lca = query(a, b);
    ll ans = 0;
    if(lca == a || lca == b) {
      if(lca == b) swap(a, b);
      ans = max(ans, x[b][0]);
      for(ll i = 19; i >= 0; i--) {
        if(parent[i][b] >= 0 && depth[parent[i][b]] >= depth[lca]) {
          ans = max(ans, mx[i][b]);
          b = parent[i][b];
        }
      }
      ans = max(ans, y[0] - y[lca]);
    } else {
      ans = max(ans, x[a][0]);
      ans = max(ans, x[b][0]);
      for(ll i = 19; i >= 0; i--) {
        if(parent[i][a] >= 0 && depth[parent[i][a]] > depth[lca]) {
          ans = max(ans, mx[i][a]);
          a = parent[i][a];
        }
      }
      for(ll i = 19; i >= 0; i--) {
        if(parent[i][b] >= 0 && depth[parent[i][b]] > depth[lca]) {
          ans = max(ans, mx[i][b]);
          b = parent[i][b];
        }
      }
      vector<ll> r;
      r.push_back(y[a]);
      r.push_back(y[b]);
      r.push_back(-1);
      sort(r.begin(), r.end(), greater<ll>());
      REP(i, 0, 3) if(r[i] != x[lca][i]) ans = max(ans, x[lca][i]);
      ans = max(ans, y[0] - y[lca]);
    }
    cout << ans << endl;
  }
}
accuracy: 1
time_ms: 320
memory_kb: 37312
final_rank: 8

code_snippet: #include <bits/stdc++.h>

using namespace std;

using int64 = long long;

int N, W[100000], Q;
vector< int > g[100000];
int dep[100000];
int64 sub[100000];
int64 heavy[3][100000];
const int LOG = 18;

int par[LOG][100000];
int64 sz[LOG][100000];

void predfs(int idx, int p, int d) {
  par[0][idx] = p;
  dep[idx] = d;
  sub[idx] += W[idx];
  for(auto &to : g[idx]) {
    if(to == p) continue;
    predfs(to, idx, d + 1);
    sub[idx] += sub[to];
    if(heavy[0][idx] < sub[to]) {
      heavy[2][idx] = heavy[1][idx];
      heavy[1][idx] = heavy[0][idx];
      heavy[0][idx] = sub[to];
    } else if(heavy[1][idx] < sub[to]) {
      heavy[2][idx] = heavy[1][idx];
      heavy[1][idx] = sub[to];
    } else if(heavy[2][idx] < sub[to]) {
      heavy[2][idx] = sub[to];
    }
  }
}

void dfs(int idx, int p) {
  for(auto &to : g[idx]) {
    if(to == p) continue;
    dfs(to, idx);
    sz[0][to] = heavy[heavy[0][idx] == sub[to]][idx];
  }
}

int lca(int x, int y) {
  if(dep[x] > dep[y]) swap(x, y);
  for(int i = LOG - 1; i >= 0; i--) {
    if((dep[y] - dep[x]) >> i & 1) y = par[i][y];
  }
  if(x == y) return x;
  for(int i = LOG - 1; i >= 0; i--) {
    if(par[i][x] != par[i][y]) {
      x = par[i][x];
      y = par[i][y];
    }
  }
  return par[0][x];
}

int main() {
  scanf("%d", &N);
  for(int i = 0; i < N; i++) {
    scanf("%d", &W[i]);
  }
  for(int i = 1; i < N; i++) {
    int x, y;
    scanf("%d %d", &x, &y);
    --x, --y;
    g[x].emplace_back(y);
    g[y].emplace_back(x);
  }
  predfs(0, -1, 0);
  dfs(0, -1);
  for(int i = 0; i + 1 < LOG; i++) {
    for(int j = 0; j < N; j++) {
      if(par[i][j] == -1) par[i + 1][j] = -1;
      else par[i + 1][j] = par[i][par[i][j]];
      if(par[i + 1][j] == -1) continue;
      sz[i + 1][j] = max(sz[i][j], sz[i][par[i][j]]);
    }
  }

  int64 all = accumulate(W, W + N, 0LL);

  scanf("%d", &Q);
  while(Q--) {
    int a, b;
    scanf("%d %d", &a, &b);
    --a, --b;
    if(dep[a] > dep[b]) swap(a, b);
    int p = lca(a, b);

    int64 ret = 0;
    if(p != a) {

      bool ng[3] = {};
      ret = max(ret, heavy[0][a]);
      ret = max(ret, heavy[0][b]);

      for(auto c : {a, b}) {
        int xx = dep[p] + 1;
        for(int i = LOG - 1; i >= 0; i--) {
          if(((dep[c] - xx) >> i) & 1) {
            ret = max(ret, sz[i][c]);
            c = par[i][c];
          }
        }
        for(int i = 0; i < 3; i++) {
          if(ng[i]) continue;
          if(sub[c] == heavy[i][p]) {
            ng[i] = true;
            break;
          }
        }
      }
      for(int i = 0; i < 3; i++) {
        if(ng[i]) continue;
        ret = max(ret, heavy[i][p]);
      }
    } else if(p != b) {
      ret = max(ret, heavy[0][b]);
      int c = b;
      int xx = dep[a] + 1;
      for(int i = LOG - 1; i >= 0; i--) {
        if(((dep[c] - xx) >> i) & 1) {
          ret = max(ret, sz[i][c]);
          c = par[i][c];
        }
      }
      ret = max(ret, sz[0][c]);
    } else {
      ret = max(ret, heavy[0][p]);
    }

    printf("%lld\n", max(ret, all - sub[p]));
  }
}
accuracy: 1
time_ms: 100
memory_kb: 23608
final_rank: 1

code_snippet: #include <bits/stdc++.h>

using namespace std;

using int64 = long long;

int N, W[100000], Q;
vector< int > g[100000];
int dep[100000];
int64 sub[100000];
int64 heavy[3][100000];
const int LOG = 20;

int par[LOG][100000];
int64 sz[LOG][100000];

void predfs(int idx, int p, int d) {
  par[0][idx] = p;
  dep[idx] = d;
  sub[idx] += W[idx];
  for(auto &to : g[idx]) {
    if(to == p) continue;
    predfs(to, idx, d + 1);
    sub[idx] += sub[to];
    if(heavy[0][idx] < sub[to]) {
      heavy[2][idx] = heavy[1][idx];
      heavy[1][idx] = heavy[0][idx];
      heavy[0][idx] = sub[to];
    } else if(heavy[1][idx] < sub[to]) {
      heavy[2][idx] = heavy[1][idx];
      heavy[1][idx] = sub[to];
    } else if(heavy[2][idx] < sub[to]) {
      heavy[2][idx] = sub[to];
    }
  }
}

void dfs(int idx, int p) {
  for(auto &to : g[idx]) {
    if(to == p) continue;
    dfs(to, idx);
    sz[0][to] = heavy[heavy[0][idx] == sub[to]][idx];
  }
}

int lca(int x, int y) {
  if(dep[x] > dep[y]) swap(x, y);
  for(int i = LOG - 1; i >= 0; i--) {
    if((dep[y] - dep[x]) >> i & 1) y = par[i][y];
  }
  if(x == y) return x;
  for(int i = LOG - 1; i >= 0; i--) {
    if(par[i][x] != par[i][y]) {
      x = par[i][x];
      y = par[i][y];
    }
  }
  return par[0][x];
}

int main() {
  scanf("%d", &N);
  for(int i = 0; i < N; i++) {
    scanf("%d", &W[i]);
  }
  for(int i = 1; i < N; i++) {
    int x, y;
    scanf("%d %d", &x, &y);
    --x, --y;
    g[x].emplace_back(y);
    g[y].emplace_back(x);
  }
  predfs(0, -1, 0);
  dfs(0, -1);
  for(int i = 0; i + 1 < LOG; i++) {
    for(int j = 0; j < N; j++) {
      if(par[i][j] == -1) par[i + 1][j] = -1;
      else par[i + 1][j] = par[i][par[i][j]];
      if(par[i + 1][j] == -1) continue;
      sz[i + 1][j] = max(sz[i][j], sz[i][par[i][j]]);
    }
  }

  int64 all = accumulate(W, W + N, 0LL);

  scanf("%d", &Q);
  while(Q--) {
    int a, b;
    scanf("%d %d", &a, &b);
    --a, --b;
    if(dep[a] > dep[b]) swap(a, b);
    int p = lca(a, b);

    int64 ret = 0;
    if(p != a) {

      bool ng[3] = {};
      ret = max(ret, heavy[0][a]);
      ret = max(ret, heavy[0][b]);

      for(auto c : {a, b}) {
        int xx = dep[p] + 1;
        for(int i = LOG - 1; i >= 0; i--) {
          if(((dep[c] - xx) >> i) & 1) {
            ret = max(ret, sz[i][c]);
            c = par[i][c];
          }
        }
        for(int i = 0; i < 3; i++) {
          if(ng[i]) continue;
          if(sub[c] == heavy[i][p]) {
            ng[i] = true;
            break;
          }
        }
      }
      for(int i = 0; i < 3; i++) {
        if(ng[i]) continue;
        ret = max(ret, heavy[i][p]);
      }
    } else if(p != b) {
      ret = max(ret, heavy[0][b]);
      int c = b;
      int xx = dep[a] + 1;
      for(int i = LOG - 1; i >= 0; i--) {
        if(((dep[c] - xx) >> i) & 1) {
          ret = max(ret, sz[i][c]);
          c = par[i][c];
        }
      }
      ret = max(ret, sz[0][c]);
    } else {
      ret = max(ret, heavy[0][p]);
    }

    printf("%lld\n", max(ret, all - sub[p]));
  }
}
accuracy: 1
time_ms: 100
memory_kb: 24440
final_rank: 2

code_snippet: #include <cstdio>
#include <vector>
#include <algorithm>
#include <functional>
#include <map>
#include <set>
#include <string>
#include <iostream>
#include <cassert>
#include <cmath>
using namespace std;

struct LCA {
        const int LOGM = 30;
        vector<int> depth;
        vector<vector<int>> parent;
        vector<pair<int, long long>> pare;
        vector<vector<long long>> parmax;
        LCA(int root, const vector<vector<int>> &g, const vector<pair<int, long long>> &pare) : pare(pare) {
                int n = g.size();
                depth.resize(n);
                parent.resize(LOGM);
                parmax.resize(LOGM);
                for (int i = 0; i < LOGM; i ++) { 
                        parent[i].resize(n);
                        parmax[i].resize(n);
                }
                function<void (int, int, int)> dfs = [&](int u, int prev, int d) {
                        parent[0][u] = prev;
                        parmax[0][u] = pare[u].second;
                        depth[u] = d;
                        for (auto v : g[u]) if (v != prev) dfs(v, u, d + 1);
                };
                dfs(root, -1, 0);
                for (int k = 0; k < LOGM - 1; k ++) {
                        for (int i = 0; i < n; i ++) {
                                if (parent[k][i] < 0) { 
                                        parent[k + 1][i] = -1;
                                } else { 
                                        parent[k + 1][i] = parent[k][parent[k][i]];
                                        if (parent[k + 1][i] >= 0) {
                                                parmax[k + 1][i] = max(parmax[k][i], parmax[k][parent[k][i]]);
                                        }
                                }
                        }
                }
        }
        int lca(int u, int v) { 
                if (depth[u] > depth[v]) swap(u, v);
                for (int k = 0; k < LOGM; k ++) {
                        if ((depth[v] - depth[u]) >> k & 1) { 
                                v = parent[k][v];
                        }
                }
                if (u == v) return u;
                for (int k = LOGM - 1; k >= 0; k --) {
                        if (parent[k][u] != parent[k][v]) {
                                u = parent[k][u];
                                v = parent[k][v];
                        }
                }
                return parent[0][u];
        }
        pair<int, long long> get(int a, int l) {
                long long res = 0;
                int d = depth[a] - depth[l] - 1;
                if (d <= 0) return { a, 0 };
                for (int k = 0; k < LOGM; k ++) {
                        if ((d >> k) & 1) {
                                res = max(res, parmax[k][a]);
                                a = parent[k][a];
                        }
                }
                return {a, res};
        }
        int dist(int u, int v) {
                return depth[u] + depth[v] - 2 * depth[lca(u, v)];
        }
};

int main() {
        int n;
        scanf("%d", &n);
        vector<int> w(n);
        vector<vector<int>> g(n);
        long long tot = 0;
        for (int i = 0; i < n; i ++) {
                scanf("%d", &w[i]);
                tot += w[i];
        }
        for (int i = 0; i < n - 1; i ++) {
                int a, b;
                scanf("%d%d", &a, &b);
                a --, b --;
                g[a].push_back(b);
                g[b].push_back(a);
        }
        vector<long long> sum(n);
        vector<long long> maxx(n);
        vector<pair<int, long long>> pare(n);
        function<void (int, int)> dfs = [&](int u, int prev) {
                pare[u].first = prev;
                sum[u] = w[u];
                vector<pair<long long, int>> val;
                int cnt = 0;
                for (auto v : g[u]) if (v != prev) {
                        dfs(v, u);
                        sum[u] += sum[v];
                        val.emplace_back(sum[v], v);
                        maxx[u] = max(maxx[u], sum[v]);
                        cnt ++;
                }
                sort(val.rbegin(), val.rend());
                if (cnt >= 2) {
                        for (auto v : g[u]) if (v != prev) {
                                if (val[0].second != v) {
                                        pare[v].second = val[0].first;
                                } else {
                                        pare[v].second = val[1].first;
                                }
                        }
                }
        };
        dfs(0, -1);
        vector<vector<pair<long long, int>>> ma(n);
        for (int i = 0; i < n; i ++) {
                for (auto v : g[i]) if (v != pare[i].first) {
                        ma[i].emplace_back(sum[v], v);
                }
                sort(ma[i].rbegin(), ma[i].rend());
        }
        LCA lca(0, g, pare);
        /*
        for (int i = 0; i < n; i ++) {
                for (int k = 0; k < 30; k ++) {
                        cerr << lca.parmax[k][i] << ' ';
                }
                cerr << endl;
        }
        */
        int q;
        scanf("%d", &q);
        while (q --) {
                int a, b;
                scanf("%d%d", &a, &b);
                a --, b --;
                int l = lca.lca(a, b);
                long long ans = tot - sum[l];

                if (a == l && b == l) { 
                        ans = max(ans, maxx[l]);
                        printf("%lld\n", ans);
                        continue;
                }

                if (a == l || b == l) {
                        if (a == l) swap(a, b);
                        ans = max(ans, maxx[a]);
                        auto geta = lca.get(a, l);
                        int va = geta.first;
                        ans = max(ans, geta.second);
                        ans = max(ans, pare[va].second);
                        printf("%lld\n", ans);
                        continue;
                }
                ans = max(ans, maxx[a]);
                ans = max(ans, maxx[b]);
                auto geta = lca.get(a, l);
                auto getb = lca.get(b, l);
                int va = geta.first;
                int vb = getb.first;
                ans = max(ans, geta.second);
                ans = max(ans, getb.second);
                int top1 = ma[l][0].second;
                int top2 = ma[l][1].second;
                if ((int) g[l].size() >= 4 || ((int) g[l].size() >= 3 && l == 0)) {
                        if (top1 == va) {
                                if (top2 == vb) {
                                        ans = max(ans, ma[l][2].first);
                                } else {
                                        ans = max(ans, ma[l][1].first);
                                }
                        } else if (top1 == vb) {
                                if (top2 == va) {
                                        ans = max(ans, ma[l][2].first);
                                } else {
                                        ans = max(ans, ma[l][1].first);
                                }
                        } else {
                                ans = max(ans, ma[l][0].first);
                        }
                }
                printf("%lld\n", ans);
        }
        return 0;
}
accuracy: 1
time_ms: 140
memory_kb: 53980
final_rank: 4

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define int long long

const int MAX_N = 100010;
const int LOG_N = 22;

using Pi = pair<int, int>;
using vint = vector<int>;

int N, Q;
int w[MAX_N];
vint graph[MAX_N];

int subsz[MAX_N];
int depth[MAX_N];
vector<Pi> chdat[MAX_N];

int par[LOG_N][MAX_N];
int mxw[LOG_N][MAX_N];

int getchw(int u, int ch1 = -1, int ch2 = -1) {
  for(Pi p : chdat[u]) {
    if(p.second != ch1 && p.second != ch2) return p.first;
  }
  return 0;
}

void init() {
  memset(par, -1, sizeof(par));
  function<void(int, int, int)> dfs = [&dfs](int u, int p, int d) {
    par[0][u] = p;
    depth[u] = d;
    subsz[u] = w[u];
    for(int v : graph[u]) {
      if(v == p) continue;
      dfs(v, u, d+1);
      subsz[u] += subsz[v];
      chdat[u].emplace_back(subsz[v], v);
    }
    sort(chdat[u].rbegin(), chdat[u].rend());
  };
  dfs(0, -1, 0);
  for(int i = 1; i < N; ++i) {
    int p = par[0][i];
    mxw[0][i] = getchw(p, i);
  }
  for(int i = 0; i+1 < LOG_N; ++i) {
    for(int v = 0; v < N; ++v) {
      if(par[i][v] == -1) {
	par[i+1][v] = -1;
	mxw[i+1][v] = -1;
      } else {
	par[i+1][v] = par[i][par[i][v]];
	mxw[i+1][v] = max(mxw[i][par[i][v]], mxw[i][v]);
      }
    }
  }
}

int ask(int u, int v) {
  if(depth[u] > depth[v]) swap(u, v);
  int res = getchw(v);
  for(int i = 0; i < LOG_N; ++i) {
    if(((depth[v]-depth[u])>>i)&1) {
      res = max(res, mxw[i][v]);
      v = par[i][v];
    }
  }
  if(u == v) return max(res, subsz[0]-subsz[u]);

  res = max(res, getchw(u));
  for(int i = LOG_N-1; i >= 0; --i) {
    if(par[i][u] != par[i][v]) {
      res = max(res, mxw[i][u]);
      res = max(res, mxw[i][v]);
      u = par[i][u];
      v = par[i][v];
    }
  }

  int lca = par[0][u];
  return max({res, subsz[0]-subsz[lca], getchw(lca, u, v)});
}

signed main() {
  scanf("%lld", &N);
  for(int i = 0; i < N; ++i) scanf("%lld", &w[i]);
  for(int i = 0; i < N-1; ++i) {
    int u, v;
    scanf("%lld %lld", &u, &v);
    --u, --v;
    graph[u].push_back(v);
    graph[v].push_back(u);
  }
  init();
  scanf("%lld", &Q);
  for(int i = 0; i < Q; ++i) {
    int a, b;
    scanf("%lld %lld", &a, &b);
    --a, --b;
    printf("%lld\n", ask(a, b));
  }
  return 0;
}
accuracy: 1
time_ms: 140
memory_kb: 50996
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define _MACRO(_1, _2, _3, NAME, ...) NAME
#define _repl(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define _rep(i,n) _repl(i,0,n)
#define rep(...) _MACRO(__VA_ARGS__, _repl, _rep)(__VA_ARGS__)
#define mp make_pair
#define pb push_back
#define all(x) begin(x),end(x)
#define uniq(x) sort(all(x)),(x).erase(unique(all(x)),end(x))
#define fi first
#define se second
#define dbg(...) _dbg(#__VA_ARGS__, __VA_ARGS__)
void _dbg(string){cerr<<endl;}
template<class H,class... T> void _dbg(string s,H h,T... t){int l=s.find(',');cerr<<s.substr(0,l)<<" = "<<h<<", ";_dbg(s.substr(l+1),t...);}
template<class T,class U> ostream& operator<<(ostream &o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream &o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

const int N = 100005;

vector<int> tree[N];

template<int SZ>
class HLDecomp {
public:
  int n;
  void dfs(const int root){
    stack<pair<int,bool> > st;
    par[root] = -1;
    dep[root] = 0;
    st.push({root,false});
    while(!st.empty()){
      int v = st.top().first;
      bool &b = st.top().second;
      if(!b){
        // initial visit of v
        b = true;
        for(int u : tree[v]) if(u != par[v]){
          par[u] = v;
          dep[u] = dep[v] + 1;
          st.push({u, false});
        }
      }
      else {
        // second visit
        st.pop();
        int cur_max = 0;
        for(int u : tree[v]) if(u != par[v]){
          sub_sz[v] += sub_sz[u];
          if(sub_sz[u] > cur_max){
            cur_max = sub_sz[u];
            heavy_child[v] = u;
          }
        }
      }
    }
  }
  void bfs(const int root){
    int cnt = 0;
    queue<int> q;
    q.push(root);
    while(!q.empty()){
      int h = q.front(); q.pop();
      for(int i=h; i!=-1; i = heavy_child[i]){
        vid[i] = cnt++;
        vid2idx[vid[i]] = i;
        chain_head[i] = h;
        for(int to : tree[i]) if(to!=par[i] && to!=heavy_child[i]) q.push(to);
      }
    }
  }

  int par[SZ], dep[SZ], sub_sz[SZ], heavy_child[SZ], vid[SZ], vid2idx[SZ], chain_head[SZ];
  HLDecomp(){}
  HLDecomp(const int _n) : n(_n) {
    assert(n<=SZ);
    fill(sub_sz, sub_sz+n, 1);
    fill(heavy_child, heavy_child+n, -1);
  }
  void add_edge(const int u, const int v){
    tree[u].push_back(v);
    tree[v].push_back(u);
  }
  void build(const int root = 0){
    dfs(root);
    bfs(root);
  }

  // 閉区間注意 SegTreeの区間 r+1 必要かも
  void for_each_vertex(int u, int v, const function<void(int,int)> &f) const {
    while(true){
      if(vid[u] > vid[v]) swap(u,v);
      f(max(vid[chain_head[v]], vid[u]), vid[v]);
      if(chain_head[u] != chain_head[v]) v = par[chain_head[v]];
      else break;
    }
  }
  int lca(int u, int v) const {
    while(true){
      if(vid[u] > vid[v]) swap(u,v);
      if(chain_head[u] == chain_head[v]) return u;
      v = par[chain_head[v]];
    }
  }
};

HLDecomp<N> hl;
vector<pair<long,int>> lval[N];
long hval[N];
long w[N];
long ch_max[N];
long pa_max[N];
long tw;

using P = pair<long,int>;

class SegTree {
public:
  int n;
  vector<vector<P>> data;
  vector<P> op(const vector<P> &lh, const vector<P> &rh) const {
    vector<P> ret;
    for(auto p : lh) ret.pb(p);
    for(auto p : rh) ret.pb(p);
    sort(all(ret), greater<P>());
    if(ret.size()>=4) ret.resize(3);
    return ret;
  }
  SegTree(int m){
    n=1;
    while(n<m) n*=2;
    data.resize(2*n);
    rep(i,m) data[i+n] = lval[hl.vid2idx[i]];
    for(int i=n-1; i>0; i--) data[i] = op(data[i*2], data[i*2+1]);
  }
  vector<P> query(int l, int r) const {
    vector<P> v = {};
    for(l+=n, r+=n; l<r; l/=2, r/=2){
      if(l&1) v = op(v, data[l++]);
      if(r&1) v = op(data[--r], v);
    }
    return v;
  }
};

long dfs(int v, int pre){
  ch_max[v] = 0;
  long ret = w[v];
  for(auto nx : tree[v]) if(nx != pre){
    long r = dfs(nx, v);
    ch_max[v] = max(ch_max[v], r);
    ret += r;
    if(nx == hl.heavy_child[v]) hval[v] = r;
    else lval[v].push_back({r, nx});
  }
  sort(all(lval[v]), greater<P>());
  if(lval[v].size()>=4) lval[v].resize(3);
  pa_max[v] = tw - ret;
  return ret;
}


int main(){
  int n;
  cin>>n;
  rep(i,n) scanf("%ld", w+i);
  tw = accumulate(w, w+n, 0L);
  hl = HLDecomp<N>(n);

  rep(i,n-1){
    int a,b;
    scanf("%d %d", &a, &b);
    a--;b--;
    hl.add_edge(a,b);
  }

  hl.build();
  dfs(0, -1);

  SegTree st(n);

  int q;
  scanf("%d", &q);
  rep(_,q){
    int a,b;
    scanf("%d %d", &a, &b);
    a--;b--;
    if(a==b){
      cout << max(ch_max[a], pa_max[a]) << "\n";
      continue;
    }
    int cp = hl.lca(a,b);

    long cand;
    if(cp == a) cand = ch_max[b];
    else if(cp == b) cand = ch_max[a];
    else cand = max(ch_max[a], ch_max[b]);

    cand = max(cand, pa_max[cp]);

    hl.for_each_vertex(a, b, [&](auto l, auto r){
      cand = max(cand, hval[hl.vid2idx[r]]);
      auto v = st.query(l ,r+1);
      // dbg(cand, hl.vid2idx[l], hl.vid2idx[r], hval[hl.vid2idx[r]], pa_max[hl.vid2idx[l]], v);
      for(auto &p : v){
        if(hl.lca(p.second,a) != p.second && hl.lca(p.second,b) != p.second){
          cand = max(cand, p.first);
          return;
        }
      }
    });
    printf("%ld\n", cand);
  }

  return 0;
}
accuracy: 1
time_ms: 330
memory_kb: 30108
final_rank: 5

code_snippet: #include<bits/stdc++.h>
using namespace std;

#define int long long

#define rep(i,n) for(int i=0;i<(n);i++)
#define pb push_back
#define all(v) (v).begin(),(v).end()
#define fi first
#define se second
typedef vector<int>vint;
typedef pair<int,int>pint;
typedef vector<pint>vpint;

template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}

const int INF=1001001001001001001ll;

int par[20][111111];
int A[111111];

int N;
vint G[111111];

int dep[111111];
int latte[111111];
int dp[20][111111];
vint lis[111111];
void dfs(int v,int p,int d){
    dep[v]=d;
    par[0][v]=p;
    latte[v]=A[v];
    lis[v].pb(0);
    lis[v].pb(0);
    for(auto u:G[v]){
        if(u==p)continue;
        dfs(u,v,d+1);
        latte[v]+=latte[u];
        lis[v].pb(latte[u]);
    }
}

int lca(int a,int b){
    if(dep[a]<dep[b])swap(a,b);
    rep(i,20)if((dep[a]-dep[b])>>i&1)a=par[i][a];
    if(a==b)return a;
    for(int i=19;i>=0;i--)if(par[i][a]!=par[i][b])a=par[i][a],b=par[i][b];
    return par[0][a];
}

signed main(){
    cin>>N;
    rep(i,N)cin>>A[i];
    rep(i,N-1){
        int a,b;
        cin>>a>>b;
        a--;b--;
        G[a].pb(b);G[b].pb(a);
    }

    dfs(0,-1,0);

    rep(i,N){
        sort(all(lis[i]));
        reverse(all(lis[i]));
    }
    for(int i=1;i<N;i++){
        int p=par[0][i];
        if(lis[p][0]==latte[i]){
            dp[0][i]=lis[p][1];
        }
        else{
            dp[0][i]=lis[p][0];
        }
    }


    rep(i,19){
        rep(j,N){
            if(par[i][j]==-1){
                par[i+1][j]=-1;
                dp[i+1][j]=dp[i][j];
            }
            else{
                par[i+1][j]=par[i][par[i][j]];
                dp[i+1][j]=max(dp[i][par[i][j]],dp[i][j]);
            }
        }
    }


    int sumall=accumulate(A,A+N,0ll);


    int Q;cin>>Q;
    while(Q--){
        int a,b;
        cin>>a>>b;a--;b--;
        int p=lca(a,b);
        int ans=0;
        rep(lattemalta,2){
            swap(a,b);
            int x=a;
            if(a==p)continue;
            chmax(ans,lis[a][0]);
            int d=dep[x]-dep[p]-1;
            rep(i,20){
                if(d>>i&1){
                    chmax(ans,dp[i][x]);
                    x=par[i][x];
                }
            }
            a=x;



        }

        {
            bool flaga=false,flagb=false;
            for(auto x:lis[p]){
                if(!flaga&&x==latte[a]){
                    flaga=true;
                    continue;
                }
                if(!flagb&&x==latte[b]){
                    flagb=true;
                    continue;
                }
                chmax(ans,x);
                break;
            }
        }
        chmax(ans,sumall-latte[p]);
        cout<<ans<<endl;
    }
    return 0;
}
accuracy: 1
time_ms: 330
memory_kb: 50168
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll=int64_t;
//#define int ll

#define FOR(i,a,b) for(int i=int(a);i<int(b);i++)
#define REP(i,b) FOR(i,0,b)
#define MP make_pair
#define PB push_back
#define ALL(x) x.begin(),x.end()
#ifdef MAROON_LOCAL
#define cerr (cerr<<"-- line "<<__LINE__<<" -- ")
#else
class CerrDummy{}cerrDummy;
template<class T>
CerrDummy& operator<<(CerrDummy&cd,const T&){
	return cd;
}
using charTDummy=char;
using traitsDummy=char_traits<charTDummy>;
CerrDummy& operator<<(CerrDummy&cd,basic_ostream<charTDummy,traitsDummy>&(basic_ostream<charTDummy,traitsDummy>&)){
	return cd;
}
#define cerr cerrDummy
#endif
#define REACH cerr<<"reached"<<endl
#define DMP(x) cerr<<#x<<":"<<x<<endl
#define ZERO(x) memset(x,0,sizeof(x))
#define ONE(x) memset(x,-1,sizeof(x))

using pi=pair<int,int>;
using vi=vector<int>;
using ld=long double;

template<class T,class U>
ostream& operator<<(ostream& os,const pair<T,U>& p){
	os<<"("<<p.first<<","<<p.second<<")";
	return os;
}

template<class T>
ostream& operator <<(ostream& os,const vector<T>& v){
	os<<"[";
	REP(i,(int)v.size()){
		if(i)os<<",";
		os<<v[i];
	}
	os<<"]";
	return os;
}

ll read(){
	ll i;
	scanf("%" SCNd64,&i);
	return i;
}

void printSpace(){
	printf(" ");
}

void printEoln(){
	printf("\n");
}

void print(ll x,int suc=1){
	printf("%" PRId64,x);
	if(suc==1)
		printEoln();
	if(suc==2)
		printSpace();
}

string readString(){
	static char buf[3341000];
	scanf("%s",buf);
	return string(buf);
}

char* readCharArray(){
	static char buf[3341000];
	static int bufUsed=0;
	char* ret=buf+bufUsed;
	scanf("%s",ret);
	bufUsed+=strlen(ret)+1;
	return ret;
}

template<class T,class U>
void chmax(T& a,U b){
	if(a<b)
		a=b;
}

template<class T,class U>
void chmin(T& a,U b){
	if(b<a)
		a=b;
}

template<class T>
T Sq(const T& t){
	return t*t;
}

#define CAPITAL
void Yes(bool ex=true){
	#ifdef CAPITAL
	cout<<"YES"<<endl;
	#else
	cout<<"Yes"<<endl;
	#endif
	if(ex)exit(0);
}
void No(bool ex=true){
	#ifdef CAPITAL
	cout<<"NO"<<endl;
	#else
	cout<<"No"<<endl;
	#endif
	if(ex)exit(0);
}

const ll infLL=LLONG_MAX/3;

#ifdef int
const int inf=infLL;
#else
const int inf=INT_MAX/2-100;
#endif

enum ClusterType{
	NONE,
	BASE,
	RAKE,
	COMPRESS,
	HARDRAKE,
	SELECTRAKE
};
template<class Info>
struct TopTree{
	struct Cluster{
		TopTree* belongingTree;
		ClusterType type;
		Cluster *l,*r,*m,*p;
		Info info,tmpInfo;
		int a,b;
		Cluster(TopTree* tree):info(-1,-1),tmpInfo(-1,-1){
			belongingTree=tree;
			Clear();
		}
		void Clear(){
			type=NONE;
			l=nullptr;
			r=nullptr;
			m=nullptr;
			p=nullptr;
			info=Info(-1,-1);
			tmpInfo=Info(-1,-1);
			a=-1;
			b=-1;
		}
		void UpdateHandles(){
			if(type==BASE){
				belongingTree->handles[a]=this;
				belongingTree->handles[b]=this;
			}else if(type==COMPRESS){
				belongingTree->handles[l->a]=this;
				belongingTree->handles[l->b]=this;
				belongingTree->handles[r->a]=this;
				belongingTree->handles[r->b]=this;
			}
		}
		void Update(){
			if(type==COMPRESS){
				if(m){
					tmpInfo=Info(l->a,l->b);
					tmpInfo.Join(l->a,l->b,m->a,m->b,m->info,l->a,l->b,l->info,RAKE);
				}
				a=l->a;
				b=r->b;
				UpdateHandles();
				info=Info(a,b);
				info.Join(a,b,l->a,l->b,m?tmpInfo:l->info,r->a,r->b,r->info,COMPRESS);
			}else if(type==RAKE){
				a=r->a;
				b=r->b;
				info=Info(a,b);
				info.Join(a,b,l->a,l->b,l->info,r->a,r->b,r->info,RAKE);
			}else if(type==HARDRAKE){
				int la=l->a,lb=l->b;
				int ra=r->a,rb=r->b;
				if(la==ra||la==rb)swap(la,lb);
				if(lb==ra)swap(ra,rb);
				a=ra;
				b=rb;
				info=Info(a,b);
				info.Join(a,b,la,lb,l->info,ra,rb,r->info,RAKE);
			}
		}
		void Reverse(){
			swap(a,b);
		}
		void Normalize(){
			if(type==BASE){
			}else{
				if(type==COMPRESS){
					bool updMid=false;
					if(r->a==a||r->b==a){
						swap(l,r);
						updMid=true;
					}
					if(l->a!=a)l->Reverse();
					if(r->b!=b)r->Reverse();
					if(m&&updMid){
						tmpInfo=Info(l->a,l->b);
						tmpInfo.Join(l->a,l->b,m->a,m->b,m->info,l->a,l->b,l->info,RAKE);
					}
					info.Split(a,b,l->a,l->b,m?tmpInfo:l->info,r->a,r->b,r->info,COMPRESS);
					if(m)tmpInfo.Split(l->a,l->b,m->a,m->b,m->info,l->a,l->b,l->info,RAKE);
				}else if(type==RAKE){
					info.Split(a,b,l->a,l->b,l->info,r->a,r->b,r->info,RAKE);
				}else if(type==HARDRAKE){
					int la=l->a,lb=l->b;
					int ra=r->a,rb=r->b;
					if(la==ra||la==rb)swap(la,lb);
					if(lb==ra)swap(ra,rb);
					info.Split(a,b,la,lb,l->info,ra,rb,r->info,RAKE);
				}
			}
		}
		Cluster* Select(int&xa,int&xb,Info&x,int&ya,int&yb,Info&y){
			Normalize();
			if(type==BASE){
				return this;
			}else{
				if(type==COMPRESS){
					Info lTmp(l->b,l->a),rTmp(r->a,r->b);
					if(xa==xb)lTmp=l->info;
					else lTmp.Join(l->b,l->a,xa,xb,x,l->b,l->a,l->info,SELECTRAKE);
					if(ya==yb)rTmp=r->info;
					else rTmp.Join(r->a,r->b,yb,ya,y,r->a,r->b,r->info,SELECTRAKE);
					if(m){
						Info mTmp(l->a,l->b);
						mTmp.Join(l->a,l->b,m->a,m->b,m->info,l->a,l->b,lTmp,RAKE);
						bool s=Info::Select(l->a,l->b,mTmp,r->a,r->b,rTmp,COMPRESS);
						if(s){
							xa=l->a,xb=l->b,x=mTmp;
							return r;
						}else{
							mTmp=Info(m->a,m->b);
							mTmp.Join(m->a,m->b,r->b,r->a,rTmp,m->a,m->b,m->info,RAKE);
							s=Info::Select(m->a,m->b,mTmp,l->a,l->b,lTmp,RAKE);
							if(s){
								ya=m->b,yb=m->a,y=mTmp;
								return l;
							}else{
								Info lrTmp(r->b,r->a);
								lrTmp.Join(r->b,r->a,l->a,l->b,lTmp,r->b,r->a,rTmp,RAKE);
								xa=m->a,xb=m->a,x=Info(-1,-1),ya=r->a,yb=r->b,y=lrTmp;
								return m;
							}
						}
					}else{
						bool s=Info::Select(l->a,l->b,lTmp,r->a,r->b,rTmp,COMPRESS);
						if(s){
							xa=l->a,xb=l->b,x=lTmp;
							return r;
						}
						else{
							ya=r->a,yb=r->b,y=rTmp;
							return l;
						}
					}
				}else if(type==RAKE){
					Info w(l->a,l->b);
					if(ya==yb)w=l->info;
					else w.Join(l->a,l->b,yb,ya,y,l->a,l->b,l->info,SELECTRAKE);
					bool s=Info::Select(l->a,l->b,w,r->a,r->b,r->info,RAKE);
					if(s){
						xa=r->a,xb=r->a,x=Info(-1,-1),ya=l->b,yb=l->a,y=w;
						return r;
					}else{
						w=Info(r->a,r->b);
						if(ya==yb)w=r->info;
						else w.Join(r->a,r->b,yb,ya,y,r->a,r->b,r->info,RAKE);
						xa=l->a,xb=l->a,x=Info(-1,-1),ya=r->b,yb=r->a,y=w;
						return l;
					}
				}else if(type==HARDRAKE){
					int la=l->a,lb=l->b;
					int ra=r->a,rb=r->b;
					if(la==ra||la==rb)swap(la,lb);
					if(lb==ra)swap(ra,rb);
					Info lTmp(la,lb),rTmp(ra,rb);
					if(ya==yb)lTmp=l->info;
					else lTmp.Join(la,lb,yb,ya,y,la,lb,l->info,SELECTRAKE);
					if(xa==xb)rTmp=r->info;
					else rTmp.Join(rb,ra,xa,xb,x,rb,ra,r->info,SELECTRAKE);
					bool s=Info::Select(la,lb,lTmp,ra,rb,rTmp,RAKE);
					if(s){
						if(ra==r->a){
							ya=lb,yb=la,y=lTmp;
							return r;
						}else{
							ya=xb,yb=xa,y=x;
							xa=la,xb=lb,x=lTmp;
							return r;
						}
					}else{
						lTmp=Info(ra,rb);
						if(ya==yb)lTmp=rTmp;
						else lTmp.Join(ra,rb,yb,ya,y,ra,rb,rTmp,RAKE);
						if(la==l->a){
							xa=la,xb=la,x=Info(-1,-1),ya=rb,yb=ra,y=lTmp;
							return l;
						}else{
							xa=ra,xb=rb,x=lTmp,ya=la,yb=la,y=Info(-1,-1);
							return l;
						}
					}
				}
			}
			assert(false);
		}
		int Pos(){
			Cluster *x=p;
			if(!x)return 0;
			else if(x->l==this)return -1;
			else if(x->r==this)return 1;
			else if(x->m==this)return -2;
			assert(false);
		}
		bool LinkedToParent(){
			return p&&(p->type!=type||p->m==this);
		}
		void Rotate(){
			Cluster *q=p,*c;
			if(Pos()==1){
				c=l;
				l=q;
				q->r=c; 
			}else{
				c=r;
				r=q;
				q->l=c;
			}
			if(c){
				if(c->p)c->p=q;
			}
			int w=p->Pos();
			p=p->p;
			q->p=this;
			Cluster *x=p;
			if(x){
				if(w==1)x->r=this;
				else if(w==-1)x->l=this;
				else if(w==-2)x->m=this;
			}
			q->Update();
		}
		void Splay(Cluster* guard){
			while(p&&p!=guard&&!LinkedToParent()){
				Cluster *q=p->p;
				if(q&&q!=guard&&!p->LinkedToParent()){
					if(Pos()==p->Pos()){
						p->Rotate();
					}else{
						Rotate();
					}
					Rotate();
				}else{
					Rotate();
				}
			}
			Update();
		}
		void Destroy(){
			info.Destroy(a,b);
		}
	};
	vector<Cluster*> handles;
	vector<Cluster> clusterBuf;
	vi ptrBuf;
	vi deg;
	vector<Cluster*> hardRakeClusters,needUpdateClusters;
	Cluster* selectRoot;
	TopTree(){}
	TopTree(int n){
		Init(n);
	}
	int vertNum,edgeNum;
	void Init(int n){
		int s=n*2+10;
		clusterBuf=vector<Cluster>(s,Cluster(this));
		REP(i,s)ptrBuf.PB(i);
		deg=vi(n,0);
		handles=vector<Cluster*>(n,nullptr);
		vertNum=n;
		edgeNum=0;
		selectRoot=nullptr;
	}
	Cluster* GetNew(){
		Cluster *res=clusterBuf.data()+ptrBuf.back();
		ptrBuf.pop_back();
		res->Clear();
		return res;
	}
	void Recycle(Cluster* ptr){
		ptrBuf.PB(ptr-clusterBuf.data());
	}
	void ClearHardRakeClusters(){
		while(!hardRakeClusters.empty()){
			Cluster* x=hardRakeClusters.back();
			hardRakeClusters.pop_back();
			x->Normalize();
			Recycle(x);
		}
		while(!needUpdateClusters.empty()){
			Cluster* x=needUpdateClusters.back();
			needUpdateClusters.pop_back();
			x->Update();
		}
	}
	void Rectify(Cluster* x,Cluster* guard){
		Cluster* p=x->p;
		if(p!=nullptr){
			Rectify(p,guard);
			if(p==guard&&p->r==x){
				p->Reverse();
				p->Normalize();
			}
		}
		x->Normalize();
	}
	Cluster* CreateCompressCluster(Cluster*l,Cluster*r,Cluster*m){
		auto p=GetNew();
		p->type=COMPRESS;
		p->l=l;
		l->p=p;
		p->r=r;
		r->p=p;
		p->m=m;
		if(m){
			m->p=p;
		}
		p->Update();
		return p;
	}
	Cluster* CreateRakeCluster(Cluster*l,Cluster*r){
		if(!l)return r;
		if(!r)return l;
		auto p=GetNew();
		p->type=RAKE;
		p->l=l;
		l->p=p;
		p->r=r;
		r->p=p;
		p->Update();
		return p;
	}
	Cluster* CreateHardRakeCluster(Cluster*l,Cluster*r){
		if(!l)return r;
		auto p=GetNew();
		hardRakeClusters.PB(p);
		p->type=HARDRAKE;
		p->l=l;
		p->r=r;
		p->Update();
		return p;
	}
	void SoftExpose(int v,Cluster* guard){
		if(handles[v]==guard)return;
		Rectify(handles[v],guard);
		Cluster *x=handles[v],*tmp=x;
		if(x->type==COMPRESS)x->Splay(guard);
		while(x->LinkedToParent()){
			Cluster* p=x->p;
			if(p->type==RAKE){
				p->Splay(nullptr);
				if(x->p!=p)
					x->p->Splay(p);
				x=p;
			}
			x=x->p;
			x->Splay(guard);
		}
		x=tmp;
		while(x->LinkedToParent()){
			Cluster* m=nullptr;
			Cluster* y=x->p;
			if(y->type==RAKE){
				Cluster*p=x->p;
				if(x->Pos()<0){
					m=p->r;
				}else{
					m=p->l;
				}
				y=p->p;
				if(y->type==RAKE){
					Cluster*q=p->p;
					if(p->Pos()<0){
						m=CreateRakeCluster(m,q->r);
					}else{
						m=CreateRakeCluster(m,q->l);
					}
					y=q->p;
					Recycle(q);
				}
				Recycle(p);
			}
			m=CreateRakeCluster(m,y->l);
			y->l->UpdateHandles();
			y->l=x;
			x->p=y;
			y->m=m;
			m->p=y;
			y->Update();
			x=y;
		}
		if(tmp->type==BASE)tmp=tmp->p;
		if(tmp){
			tmp->Splay(guard);
		}
		if(guard)guard->Update();
	}
	bool SoftExpose(int a,int b){
		if(deg[b]==0){
			return false;
		}else if(deg[a]==0){
			SoftExpose(b,nullptr);
			if(handles[b]->a==b){
				handles[b]->Reverse();
				handles[b]->Normalize();
			}
			return false;
		}else if(deg[b]==1){
			SoftExpose(b,nullptr);
			if(handles[b]->a==b){
				handles[b]->Reverse();
				handles[b]->Normalize();
			}
			SoftExpose(a,nullptr);
			if(handles[a]==handles[b]){
				return true;
			}else{
				if(handles[a]->a==a){
					handles[a]->Reverse();
					handles[a]->Normalize();
				}
				return false;
			}
		}else{
			SoftExpose(b,nullptr);
			SoftExpose(a,handles[b]);
			if(handles[a]==handles[b]){
				if(handles[a]->b==a){
					handles[a]->Reverse();
					handles[a]->Normalize();
				}
				return true;
			}else if(handles[a]==handles[b]->l){
				return true;
			}else{
				if(handles[a]->a==a){
					handles[a]->Reverse();
					handles[a]->Normalize();
				}
				return false;
			}
		}
	}
	void SoftExpose(int v){
		if(deg[v]==0){
			//do nothing
		}else{
			SoftExpose(v,nullptr);
			if(handles[v]->a==v){
				handles[v]->Reverse(); 
				handles[v]->Normalize();
			}
		}
	}
	Cluster* HardExpose(int a,int b){
		if(deg[b]==1){
			return handles[a];
		}else if(deg[a]==1){
			needUpdateClusters.PB(handles[b]);
			auto x=handles[b]->l;
			x=CreateHardRakeCluster(handles[b]->m,x);
			x=CreateHardRakeCluster(handles[b]->r,x);
			return x;
		}else{
			needUpdateClusters.PB(handles[b]);
			needUpdateClusters.PB(handles[a]);
			auto x=handles[a]->r;
			x=CreateHardRakeCluster(handles[a]->l,x);
			x=CreateHardRakeCluster(handles[a]->m,x);
			x=CreateHardRakeCluster(handles[b]->m,x);
			x=CreateHardRakeCluster(handles[b]->r,x);
			return x;
		}
	}
	Cluster* HardExpose(int v){
		return HardExpose(handles[v]->a,v);
	}
	Cluster* ExposePath(int a,int b){
		assert(!selectRoot);
		ClearHardRakeClusters();
		if(deg[a]>deg[b])swap(a,b);
		bool connected=SoftExpose(a,b);
		if(!connected)return nullptr;
		return HardExpose(a,b);
	}
	Info* Expose(int a,int b){
		//cerr<<"expose "<<a<<" "<<b<<endl;
		if(a==b)return Expose(a);
		Cluster*x=ExposePath(a,b);
		if(x)return &(x->info);
		else return nullptr;
	}
	Cluster* ExposeVertex(int v){
		assert(!selectRoot);
		ClearHardRakeClusters();
		SoftExpose(v);
		if(deg[v]==0)return nullptr;
		return HardExpose(v);
	}
	Info* Expose(int v){
		//cerr<<"expose "<<v<<endl;
		Cluster*x=ExposeVertex(v);
		if(x)return &(x->info);
		else return nullptr;
	}
	bool Connected(int a,int b){
		//cerr<<"connected "<<a<<" "<<b<<endl;
		assert(!selectRoot);
		ClearHardRakeClusters();
		if(deg[a]>deg[b])swap(a,b);
		return SoftExpose(a,b);
	}
	template <class... Args>
	bool Link(int a,int b,Args... args){
		assert(!selectRoot);
		ClearHardRakeClusters();
		if(deg[a]>deg[b])swap(a,b);
		//cerr<<"link "<<a<<" "<<b<<endl;
		bool connected=SoftExpose(a,b);
		if(connected)return false;
		Cluster* u=handles[a],*v=handles[b];
		Cluster* x=GetNew();
		x->type=BASE;
		x->a=a;
		x->b=b;
		x->info=Info(a,b);
		x->info.Create(a,b,args...);
		x->UpdateHandles();
		Cluster* y=nullptr;
		if(deg[a]==0){
			y=x;
		}else if(deg[a]==1){
			y=CreateCompressCluster(u,x,nullptr);
		}else{
			u->r->Reverse();
			u->r->UpdateHandles();
			y=CreateCompressCluster(u->l,x,CreateRakeCluster(u->r,u->m));
			Recycle(u);
		}
		if(deg[b]==0){
		}else if(deg[b]==1){
			v->Reverse();
			v->Normalize();
			CreateCompressCluster(y,v,nullptr);
		}else{
			v->l->UpdateHandles();
			CreateCompressCluster(y,v->r,CreateRakeCluster(v->m,v->l));
			Recycle(v);
		}
		deg[a]++;
		deg[b]++;
		edgeNum++;
		return true;
	}
	pair<Cluster*,Cluster*> SplitMiddleChild(Cluster*x){
		if(x->type!=RAKE)return MP(x,nullptr);
		while(x->type==RAKE)x=x->l;
		x->p->Splay(nullptr);
		Cluster* tmp=x->p;
		pair<Cluster*,Cluster*>  res=MP(tmp->l,tmp->r);
		Recycle(tmp);
		return res;
	}
	bool Cut(int a,int b){
		assert(!selectRoot);
		ClearHardRakeClusters();
		if(deg[a]>deg[b])swap(a,b);
		//cerr<<"cut "<<a<<" "<<b<<endl;
		bool connected=SoftExpose(a,b);
		if(!connected)return false;
		Cluster *u=handles[a],*v=handles[b];
		if(deg[b]==1){
			if(u->type!=BASE)return false;
			u->Destroy();
			Recycle(u);
			handles[a]=nullptr;
			handles[b]=nullptr;
		}else if(deg[a]==1){
			if(v->l->type!=BASE)return false;
			if(deg[b]==2){
				v->r->p=nullptr;
				v->r->UpdateHandles();
			}else{
				pair<Cluster*,Cluster*> z=SplitMiddleChild(v->m);
				CreateCompressCluster(z.first,v->r,z.second);
			}
			v->l->Destroy();
			Recycle(v->l);
			Recycle(v);
			handles[a]=nullptr;
		}else{
			if(u->r->type!=BASE)return false;
			if(deg[a]==2){
				u->l->p=nullptr;
				u->l->UpdateHandles();
			}else{
				pair<Cluster*,Cluster*> z=SplitMiddleChild(u->m);
				z.first->Reverse();
				CreateCompressCluster(u->l,z.first,z.second);
			}
			if(deg[b]==2){
				v->r->p=nullptr;
				v->r->UpdateHandles();
			}else{
				pair<Cluster*,Cluster*> z=SplitMiddleChild(v->m);
				CreateCompressCluster(z.first,v->r,z.second);
			}
			u->r->Destroy();
			Recycle(u->r);
			Recycle(u);
			Recycle(v);
		}
		deg[a]--;
		deg[b]--;
		edgeNum--;
		return true;
	}
	Info* PrepareForSelect(int a,int b){
		//cerr<<"prepare "<<a<<" "<<b<<endl;
		if(a==b)return PrepareForSelect(a);
		selectRoot=ExposePath(a,b);
		if(selectRoot==nullptr)return nullptr;
		return &(selectRoot->info);
	}
	Info* PrepareForSelect(int v){
		//cerr<<"prepare "<<v<<endl;
		selectRoot=ExposeVertex(v);
		if(selectRoot==nullptr)return nullptr;
		return &(selectRoot->info);
	}
	Info* Select(){
		assert(selectRoot);
		assert(!selectRoot->p);
		Cluster* cur=selectRoot;
		int xa=cur->a,xb=xa,ya=cur->b,yb=ya;
		Info x(-1,-1),y(-1,-1);
		while(1){
			Cluster*nx=cur->Select(xa,xb,x,ya,yb,y);
			if(nx==cur)break;
			cur=nx;
		}
		selectRoot=nullptr;
		return Expose(cur->a,cur->b);
	}
	int NumofVertices(){
		return vertNum;
	}
	int NumofEdges(){
		return edgeNum;
	}
};

struct InfoBase{
	private:
	int vert[2];
	void SetVertex(int a,int b){
		vert[0]=a;
		vert[1]=b;
	}
	public:
	InfoBase(int a,int b){
		SetVertex(a,b);
	}
	inline int idx(int v){
		if(vert[0]==v)return 0;
		if(vert[1]==v)return 1;
		assert(false);
	}
	inline int another(int v){
		if(vert[0]==v)return vert[1];
		if(vert[1]==v)return vert[0];
		assert(false);
	}
	inline int v0(){
		return vert[0];
	}
	inline int v1(){
		return vert[1];
	}
};

const int Nmax=100010;
ll w[Nmax];

struct Info:InfoBase{
	ll sum,_es[2],mx;
	ll&es(int x){
		return _es[idx(x)];
	}
	Info(int a,int b):InfoBase(a,b){}
	void Join(int a,int b,int la,int lb,Info&l,int ra,int rb,Info&r,ClusterType type){
		//(another(a)==b);
		//(another(b)==a);
		if(type==RAKE){
			//(a==ra);
			//(b==rb);
			//(lb==rb);
			sum=l.sum+r.sum-w[b];
			es(a)=r.es(a);
			es(b)=r.es(b)+l.sum-w[b];
			mx=max({l.mx,r.mx,l.sum-w[b]-l.es(b)});
		}else if(type==SELECTRAKE){
			//(a==ra);
			//(b==rb);
			//(lb==rb);
		}else if(type==COMPRESS){
			//(a==la);
			//(lb==ra);
			//(rb==b);
			sum=l.sum+r.sum-w[lb];
			es(a)=l.es(a);
			es(b)=r.es(b);
			mx=max(l.mx,r.mx);
		}
	}
	void Create(int a,int b){
		//(another(a)==b);
		//(another(b)==a);
		sum=w[a]+w[b];
		es(a)=es(b)=0;
		mx=0;
	}
	void Split(int a,int b,int la,int lb,Info&l,int ra,int rb,Info&r,ClusterType type){
		//(another(a)==b);
		//(another(b)==a);
		if(type==RAKE){
			//(a==ra);
			//(b==rb);
			//(lb==rb);
		}else if(type==COMPRESS){
			//(a==la);
			//(lb==ra);
			//(rb==b);
		}
	}
	void Destroy(int a,int b){
		//(another(a)==b);
		//(another(b)==a);
	}
	static bool Select(int la,int lb,Info l,int ra,int rb,Info r,ClusterType type){
		if(type==RAKE){
			//(lb==rb);
		}else if(type==COMPRESS){
			//(lb==ra);
		}
	}
};

signed main(){
	int n=read();
	REP(i,n)w[i]=read();
	TopTree<Info> tree(n);
	REP(i,n-1){
		int a=read()-1,b=read()-1;
		tree.Link(a,b);
	}
	int q=read();
	REP(i,q){
		int a=read()-1,b=read()-1;
		auto info=tree.Expose(a,b);
		print(info->mx);
	}
}
accuracy: 1
time_ms: 460
memory_kb: 39788
final_rank: 16

code_snippet: #include <bits/stdc++.h>
#define int long long
#define N 100005
using namespace std;

typedef pair<int,int> P;

class LCA{
public:
  int LOG_V=30;                 //log V (自分で決めて)
  int V;                              //言わずもがな頂点数
  vector<vector<int> > G;             //グラフの隣接リストの表現
  int root;                         //根のノード番号
  vector<vector<int> > parent;        //親を2^k回辿って到達する頂点(根を通りすぎる場合は-1とする)
  vector<int> depth;                  //根からの深さ
  int ok;
  
  LCA():V(-1){}
  LCA(int V,int root = 0):V(V),G(V),root(root),parent(LOG_V,vector<int>(V)),depth(V),ok(0){}
  
  void add_edge(int a, int b){
    assert(a < V && b < V);
    G[a].push_back(b);
    G[b].push_back(a);
  }
  
  void dfs(int v,int p,int d){
    assert(v < V);
    parent[0][v] = p;
    depth[v] = d;
    for(int to:G[v]) if(to != p) dfs(to,v,d+1);
  }
  
  //初期化
  void init(){
    ok = 1;
    //parent[0]とdepthを初期化する。
    dfs(root,-1,0);
    //parentを初期化する
    for(int k=0; k+1<LOG_V ;k++)
      for(int v=0; v<V ;v++)
        if(parent[k][v] < 0)parent[k+1][v] = -1;
        else parent[k+1][v] = parent[k][parent[k][v]];
  }
  
  //uとvのLCAを求める
  int lca(int u,int v){
    assert(ok);
    assert(u < V && v < V);
    //uとvの深さが同じになるまで親を辿る
    if(depth[u]>depth[v]) swap(u,v);
    
    for(int k=0; k<LOG_V ;k++)
      if((depth[v]-depth[u])>>k&1)v=parent[k][v];
    
    vector<int> res;
    
    if(u==v) return u;
    
    //二分探索でLCAを求める
    for(int k=LOG_V-1; k>=0 ;k--)
      if(parent[k][u] != parent[k][v]){
        u=parent[k][u];
        v=parent[k][v];
      }
    
    res.push_back(u);
    res.push_back(v);
	
    return parent[0][u];
  }  
  
};

int n, w[N], W, cost[30][N];
vector<int> G[N];
vector<P> maxw[N];

int dfs(int x, int pre){
  
  int res = 0;
  
  priority_queue<P> q;

  for(int i=0;i<G[x].size();i++){
    
    int nx = G[x][i];
    
    if( nx == pre ) continue;
    
    int v = dfs(nx ,x);
    
    q.push( P( v , nx ) );
    res += v;
  }
  
  res += w[x];
  
  if( x != 0 ) q.push( P( W - res , pre ) );
  
  for(int i=0;i<3;i++){
    
    if(q.empty()) break;
    
    maxw[x].push_back(q.top());
    
    q.pop();
  }
  
  for(int i=0;i<G[x].size();i++){
    
    int nx = G[x][i];
    
    if( nx == pre ) continue;
    
    for(int j=0;j<maxw[x].size();j++){

      int c = maxw[x][j].first;
      int node = maxw[x][j].second;
      
      if( node == pre || node == nx ) continue;
      
      cost[0][nx] = max( cost[0][nx] , c );
    }
  }
  
  return res;
}

LCA lca;

int get_anc(int node, int x){

  for(int i=0;i<30;i++)
    
    if(x>>i&1)
      node = lca.parent[i][node];
  
  return node;
}

void solve(){
  
  for(int i=0;i<n;i++) W+=w[i];
  
  dfs(0, -1);
  
  for(int i=0;i<29;i++){
    
    for(int j=0;j<n;j++){
      
      int par = lca.parent[i][j];
      
      if( par >= 0 ) cost[i+1][j] = max( cost[i][j],  cost[i][par] );
      
    }
    
  }
  
  int q;
  cin>>q;
  
  while(q--){
    
    int a, b;
    cin>>a>>b;
    a--, b--;
    
    int lca_ = lca.lca(a, b);
    
    int a1=-1, a2=-1, b1=-1, b2=-1;
    
    if( lca.depth[lca_] + 1 <= lca.depth[a] )
      a1 = get_anc( a, lca.depth[a]-lca.depth[lca_]-1 );
    
    if( lca.depth[lca_] + 2 <= lca.depth[a] )
      a2 = get_anc( a, lca.depth[a]-lca.depth[lca_]-2 );
    
    if( lca.depth[lca_] + 1 <= lca.depth[b] )
      b1 = get_anc( b, lca.depth[b]-lca.depth[lca_]-1 );
    
    if( lca.depth[lca_] + 2 <= lca.depth[b] )
      b2 = get_anc( b, lca.depth[b]-lca.depth[lca_]-2 );
    
    int ans = 0;
        
    for(int i=0;i<maxw[lca_].size();i++){
      
      int c = maxw[lca_][i].first;
      int node = maxw[lca_][i].second;
      
      if( node == a1 || node == b1 ) continue;
      
      ans = max( ans , c );
    }

    for(int i=0;i<maxw[a].size();i++){

      if(a==lca_) break;
      
      int c = maxw[a][i].first;
      int node = maxw[a][i].second;
      
      if( node == lca.parent[0][a] ) continue;
      
      ans = max( ans , c );
    }

    for(int i=0;i<maxw[b].size();i++){

      if(b==lca_) break;
      
      int c = maxw[b][i].first;
      int node = maxw[b][i].second;
      
      if( node == lca.parent[0][b] ) continue;
      
      ans = max( ans , c );
    }
    
    if( a2 != -1 ){
      
      int x = a, d = lca.depth[a] - lca.depth[a2];
      
      for(int i=0;i<30;i++){
	
	if(d>>i&1){
	  ans = max( ans, cost[i][x] );
	  x = lca.parent[i][x];
	}
      }
      
      ans = max( ans, cost[0][x] );
    }

    if( b2 != -1 ){
      
      int x = b, d = lca.depth[b] - lca.depth[b2];
      
      for(int i=0;i<30;i++){
	
	if(d>>i&1){
	  ans = max( ans, cost[i][x] );
	  x = lca.parent[i][x];
	}
      }
      
      ans = max( ans, cost[0][x] );
    }
    
    cout<<ans<<endl;
  }
  
}

signed main(){
  
  cin>>n;
  
  for(int i=0;i<n;i++) cin>>w[i];
  
  lca = LCA(n);
  
  for(int i=0;i<n-1;i++){
    int u, v;
    cin>>u>>v;
    G[u-1].push_back(v-1);
    G[v-1].push_back(u-1);
    lca.add_edge(u-1, v-1);
  }
  
  lca.init();
  
  solve();
  
  return 0;
}
accuracy: 1
time_ms: 380
memory_kb: 51752
final_rank: 15