제출 #1360481

#제출 시각아이디문제언어결과실행 시간메모리
1360481gayCat Exercise (JOI23_ho_t4)C++20
100 / 100
1874 ms246740 KiB
#include <bits/stdc++.h>

using namespace std;

using ld = long double;
using ll = long long;

const ll INF = 1e18, MOD = 1e9 + 7;

void solve();

signed main() {
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    int q = 1;
    while (q--) {
        solve();
    }
}

const int MAXN = 200000;
const int LG = 19;

vector<int> g[MAXN];
int val[MAXN], fl[MAXN], tin[MAXN], tout[MAXN];
int up[MAXN][LG], mx[MAXN][LG], num[LG][MAXN];
int timer = 1;

void ups(int v, int p) {
    up[v][0] = p;
    mx[v][0] = max(val[v], val[p]);
    tin[v] = timer++;
    for (int i = 1; i < LG; i++) {
        up[v][i] = up[up[v][i - 1]][i - 1];
        mx[v][i] = max(mx[v][i - 1], mx[up[v][i - 1]][i - 1]);
    }
    for (auto u: g[v]) {
        if (u != p) {
            fl[u] = fl[v] + 1;
            ups(u, v);
        }
    }
    tout[v] = timer++;
}

bool ch(int a, int b) {
    return tin[a] <= tin[b] && tout[a] >= tout[b];
}

int lc(int a, int b) {
    if (ch(a, b)) return a;
    if (ch(b, a)) return b;
    for (int i = LG - 1; i >= 0; i--) {
        int v = up[a][i];
        if (ch(v, b)) continue;
        a = v;
    }
    return up[a][0];
}

int gt(int a, int ds) {
    int ans = val[a];
    for (int i = LG - 1; i >= 0; i--) {
        if (ds - (1 << i) >= 0) {
            ans = max(ans, mx[a][i]);
            ds -= (1 << i);
            a = up[a][i];
        }
    }
    return ans;
}

pair<int, int> clc(int a, int b) {
    int lca = lc(a, b);
    int dist = fl[a] + fl[b] - 2 * fl[lca];
    int m = max(gt(a, fl[a] - fl[lca]), gt(b, fl[b] - fl[lca]));
    return {dist, m};
}

int sz[MAXN], par[MAXN], used[MAXN], lev[MAXN];
int ds[LG][MAXN];
int l[LG][MAXN], r[LG][MAXN];

void get_sz(int v, int p) {
    sz[v] = 1;
    for (auto u: g[v]) {
        if (u == p || used[u]) continue;
        get_sz(u, v);
        sz[v] += sz[u];
    }
}

int Find_centroid(int v, int p, int aint) {
    int next = -1;
    for (auto u: g[v]) {
        if (u == p || used[u]) continue;
        if (sz[u] > aint / 2) next = u;
    }
    if (next == -1) return v;
    return Find_centroid(next, v, aint);
}

struct sg {
    vector<ll> tree;
    void change(int v, int vl, int vr, int pos, ll x) {
        if (vr - vl == 1) {
            if (x == -INF) {
                tree[v] = x;
            } else {
                tree[v] = max(tree[v], x);
            }
            return;
        }
        int m = (vl + vr) / 2;
        if (pos < m) {
            change(2 * v, vl, m, pos, x);
        } else {
            change(2 * v + 1, m, vr, pos, x);
        }
        tree[v] = max(tree[2 * v], tree[2 * v + 1]);
    }
    ll get(int v, int vl, int vr, int lq, int rq) {
        if (vl >= rq || vr <= lq) {
            return -INF;
        }
        if (vl >= lq && vr <= rq) {
            return tree[v];
        }
        int m = (vl + vr) / 2;
        return max(get(2 * v, vl, m, lq, rq), get(2 * v + 1, m, vr, lq, rq));
    }
};

sg cnt[MAXN];

void calc(int v, int p, int f, int lv, int lf, int rf, int c, int &id) {
    ds[lv][v] = f;
    num[lv][v] = id++;
    l[lv][v] = lf;
    r[lv][v] = rf;
    for (auto u: g[v]) {
        if (u == p || used[u]) continue;
        calc(u, v, f + 1, lv, lf, rf, c, id);
    }
}

void build(int v, int p, int level) {
    get_sz(v, -1);
    v = Find_centroid(v, -1, sz[v]);
    lev[v] = level;
    par[v] = p;
    used[v] = 1;
    get_sz(v, -1);
    int id = 1;
    ds[level][v] = 0;
    num[level][v] = 0;
    cnt[v].tree.resize(4 * sz[v], -INF);
    for (auto u: g[v]) {
        if (used[u]) continue;
        calc(u, -1, 1, level, id, id + sz[u] - 1, v, id);
    }

    for (auto u: g[v]) {
        if (!used[u]) build(u, v, level + 1);
    }
}

int p[MAXN];
int del[LG][MAXN];

void upd(int c, int v, ll x) {
    if (c == -1) return;
    if (!del[lev[c]][v]) {
        cnt[c].change(1, 0, (int)cnt[c].tree.size() / 4, num[lev[c]][v], x + ds[lev[c]][v]);
    }
    upd(par[c], v, x);
}

void dfs(int v, int c) {
    int lv = lev[c];
    del[lv][v] = 1;
    cnt[c].change(1, 0, (int)cnt[c].tree.size() / 4, num[lv][v], -INF);
    for (auto u: g[v]) {
        if (lev[u] < lev[c]) continue;
        if (ds[lv][u] < ds[lv][v]) continue;
        if (del[lv][u]) continue;
        dfs(u, c);
    }
}

void deleted(int c, int v) {
    if (c == -1) return;
    dfs(v, c);
    deleted(par[c], v);
}

void get(int c, int v, ll &ans) {
    if (c == -1) return;
    auto [d, m] = clc(c, v);
    if (m > val[v]) {
        get(par[c], v, ans);
        return;
    }
    if (v == c) {
        ans = max(ans, cnt[c].tree[1] + d);
        get(par[c], v, ans);
        return;
    }
    int len = (int)cnt[c].tree.size() / 4;
    ans = max(ans, cnt[c].get(1, 0, len, 0, l[lev[c]][v]) + d);
    ans = max(ans, cnt[c].get(1, 0, len, r[lev[c]][v] + 1, len) + d);
    get(par[c], v, ans);
}

void solve() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> val[i];
        val[i]--;
        p[val[i]] = i;
    }
    for (int i = 1; i < n; i++) {
        int a, b;
        cin >> a >> b;
        a--, b--;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    ups(0, 0);

    build(0, -1, 0);

    vector<ll> dp(n, -INF);
    dp[n - 1] = 0;
    for (auto v: g[p[n - 1]]) {
        upd(v, v, 1);
    }
    deleted(p[n - 1], p[n - 1]);
    for (int i = n - 2; i >= 0; i--) {
        get(p[i], p[i], dp[i]);
        for (auto v: g[p[i]]) {
            upd(v, v, dp[i] + 1);
        }
        deleted(p[i], p[i]);
    }
    ll ans = 0;
    for (int i = 0; i < n; i++) {
        ans = max(ans, dp[i]);
    }
    cout << ans;
}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…