Apples and Snakes#12242

Apples and Snakes (Çözgüdiň düşündirişi)

Problem Author:

Andrii Kholod (Connect)

Prepared by:

Andrii Kholod (Connect)

Editorial:

Andrii Kholod (Connect)

Solution

We remove all vertices that contain snakes. After deleting the forbidden vertices, we obtain a forest. We need to maximize the sum of the weights of unique vertices in the union of no more than two simple paths. Two paths together can form up to four leaves — hence the combinations -.

For each “clean” component, we run a and compute for each vertex :

  • dp_v = the best downward branch starting at (one endpoint is ),

  • mx\_path_v = the best single path within the subtree of ,

  • up_v = the best combination of two paths in the subtree of , where at least one passes through or ends at .

Combinations through (taking the largest values among its children):

  • dp_v = a_v + \max(dp_{child}),

  • mx\_path_v = \max(mx\_path_v, a_v + \text{top-2 } dp_{child}),

  • up_v = \max(up_v, a_v + \text{top-3 } dp_{child}),

  • ans = \max(ans, a_v + \text{top-4 } dp_{child})

We also merge different subtrees using prefix maximums:

  • ans = \max(ans, \max(mx\_path_{child1} + mx\_path_{child2},\ up_{child} + a_v + dp_{other},\ a_v + dp_x + up_x))

Additionally, we combine a “ready” path from one subtree with branches from others, ensuring we never reuse the same child twice.

Finally, for each component we have mx\_path_{root}. We take the two largest of them and update once more:

  • ans = \max(ans, mx\_path_{root_1} + mx\_path_{root_2})

The asymptotic complexity of this solution is O\left(\sum deg(v) \log(deg(v))\right).

#include <bits/stdc++.h>

//#pragma GCC optimize("Ofast", "unroll-loops")
//#pragma GCC target("sse", "sse2", "sse3", "ssse3", "sse4")

#include <bits/stdc++.h>

#define all(a) a.begin(),a.end()
#define len(a) (int)(a.size())
#define mp make_pair
#define pb push_back
#define fi first
#define se second

using namespace std;

typedef pair<int, int> pii;
typedef long long ll;
typedef long double ld;
template<class T>
using vec = vector<T>;

template<typename T>
bool umin(T &a, T b) {
    if (b < a) { a = b; return true; }
    return false;
}
template<typename T>
bool umax(T &a, T b) {
    if (a < b) { a = b; return true; }
    return false;
}

#ifdef KoRoVa
#define DEBUG for (bool _FLAG = true; _FLAG; _FLAG = false)
#define LOG(...) print(#__VA_ARGS__" ::", __VA_ARGS__) << endl
template <class ...Ts> auto &print(Ts ...ts) { return ((cerr << ts << " "), ...); }
#else
#define DEBUG while (false)
#define LOG(...)
#endif

const int max_n = 2e5 + 11, inf = 1000111222;
const ll linf = inf * 1ll * inf;

int a[max_n];
int bad[max_n];
vector <int> edge[max_n];
int used[max_n];
ll dp[max_n];
ll mx_path[max_n];
ll up[max_n];
ll ans = 0;

inline void dfs (int v, int p = -1) {
    used[v] = 1;
    ll pref = 0, pref_up = 0, mx_pref = 0;
    vector <pair<ll, int>> one, cur;

    for (int to : edge[v]) {
        if (to == p || bad[to]) continue;
        dfs(to, v);
        umax(dp[v], dp[to]);
        umax(mx_path[v], mx_path[to]);
        cur.pb({dp[to], to});

        umax(up[v], up[to] + a[v]);

        if (umax(ans, up[to] + a[v] + pref)) { LOG(ans); }
        if (umax(ans, a[v] + pref_up + dp[to])) { LOG(ans, v, pref_up, dp[to]); }

        umax(pref, dp[to]);
        umax(pref_up, up[to]);
        umax(ans, mx_path[to] + mx_pref);

        umax(mx_pref, mx_path[to]);
        one.pb({mx_path[to], to});
    }

    dp[v] += a[v];
    sort(all(cur));
    reverse(all(cur));
    ll sum = a[v], now = a[v], mx = a[v];

    for (int i = 0; i < len(cur) && i < 4; i++) {
        if (i < 3) sum += cur[i].first;
        if (i < 2) mx += cur[i].first;
        now += cur[i].first;
    }

    umax(ans, now);
    umax(up[v], sum);
    umax(mx_path[v], mx);

    sort(all(one));
    reverse(all(one));

    for (int i = 0; i < len(one) && i < 3; i++) {
        umax(up[v], a[v] + one[i].first);
        for (int j = 0; j < 3 && j < len(cur); j++) {
            if (cur[j].second == one[i].second) continue;
            umax(up[v], a[v] + one[i].first + cur[j].first);
            for (int k = 0; k < 3 && k < len(cur); k++) {
                if (cur[k].second == one[i].second || j == k) continue;
                if (umax(ans, a[v] + one[i].first + cur[j].first + cur[k].first)) {
                    LOG(v, ans);
                }
            }
        }
    }

    if (umax(ans, up[v])) { LOG(v, ans); }
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    int n, m;
    cin >> n >> m;
    for (int i = 0; i < n; i++) cin >> a[i];
    for (int i = 0; i < m; i++) {
        int x; cin >> x; --x; bad[x] = 1;
    }
    for (int i = 1, u, v; i < n; i++) {
        cin >> u >> v; --u; --v;
        edge[u].pb(v);
        edge[v].pb(u);
    }

    vector<ll> gg;
    for (int i = 0; i < n; i++) {
        if (bad[i] || used[i]) continue;
        dfs(i);
        gg.pb(mx_path[i]);
    }

    sort(all(gg));
    reverse(all(gg));
    ll cur = 0;
    for (int i = 0; i < len(gg) && i < 2; i++) cur += gg[i];
    umax(ans, cur);

    cout << ans << '\n';
}

/*
KoRoVa!
*/