小紅闖地下城

onlyblues發表於2024-11-22

小紅闖地下城

題目描述

已知地下城是樹形結構,一共有 $n$ 個房間,$n−1$ 條雙向通路。入口和出口都在 $1$ 號房間,每個房間有 $1$ 只怪物,小紅進入房間後必須先擊殺怪物。

每個房間有一個通往其他房間的單向傳送陣。小紅可以使用最多 $1$ 次傳送。

當小紅透過道路或者傳送陣移動到其他房間時,將消耗 $1$ 點體力。擊殺 $1$ 只怪物同樣也需要 $1$ 點體力。

小紅初始有 $x$ 點體力。她想知道,最多可以擊殺多少隻怪物?請注意,小紅最終必須回到 $1$ 號房間離開地下城。擊殺的怪物不能復生。

輸入描述:

第一行輸入兩個正整數 $n,x$,用空格隔開,分別代表房間的數量和小紅的初始體力。

第二行輸入 $n$ 個正整數 $a_i$​,代表每個房間的傳送陣通向的房間編號。

接下來的 $n−1$ 行,每行輸入兩個正整數 $u,v$,代表房間 $u$ 和房間 $v$ 有一條通路。

$1 \leq n \leq 200000$

$1 \leq a_i​,u,v \leq n$

$1 \leq x \leq 1000000$

輸出描述:

一個整數,代表小紅可以擊殺的怪物最大數量。

示例1

輸入

3 2
2 3 1
1 2
2 3

輸出

1

說明

小紅只有 $2$ 點體力,她首先擊殺 $1$ 號房間的怪物,消耗 $1$ 點體力,然後就什麼都做不了了(如果離開 $1$ 號房間就回不來了)。

示例2

輸入

3 6
1 3 1
1 2
1 3

輸出

3

說明

小紅安排體力的流程如下:

擊殺 $1$ 號房間怪物,消耗 $1$ 體力。

移動到 $2$ 號房間,消耗 $1$ 體力。

擊殺 $2$ 號房間怪物,消耗 $1$ 體力。

傳送到 $3$ 號房間,消耗 $1$ 體力。

擊殺 $3$ 號房間怪物,消耗 $1$ 體力。

移動到 $1$ 號房間,消耗 $1$ 體力。

解題思路

  補了下兩個星期前的題,下半個學期的星期五晚上被排了課搞得打不了比賽,也沒多少時間補題,慘喵。

  可以分成兩種情況來考慮,不使用傳送門,和使用傳送門。

  先考慮不使用傳送門的情況。對於每個被遍歷過的點 $u$(不考慮根節點 $1$),在最優解中連線其父節點 $p$ 的無向邊 $(u,p)$ 必然恰好經過 $2$ 次。首先如果有向邊 $p \to u$ 經過至少 $2$ 次,意味著從 $p$ 往下至少訪問了 $2$ 次子樹 $u$,顯然我們完全可以只經過 $1$ 次的遍歷訪問子樹 $u$ 中的節點,因此 $p \to u$ 最多會經過 $1$ 次。又因為訪問子樹 $u$ 後需要從 $u$ 回到根節點,因此 $u \to p$ 至少被經過 $1$ 次。因此無向邊 $(u,p)$ 恰好被經過 $2$ 次。

  假設一共訪問了 $x$ 個節點,意味著會經過 $x-1$ 條邊,又因為每個點只擊殺一次怪物,每條邊恰好經過 $2$ 次,因此消耗的體力就是 $x + 2(x-1)$。可以發現消耗的體力只與訪問的節點數量有關,而與訪問了哪些節點無關,因此若消耗的體力不超過 $m$ 則最多能訪問 $\left\lfloor \frac{m+2}{3} \right\rfloor$ 個節點($3x-2 \leq m \Rightarrow x \leq \left\lfloor \frac{m+2}{3} \right\rfloor$)。

  再考慮使用傳送門的情況。考慮使用第 $i$ 個傳送門的最優解的方案,一定包含從 $1$ 到 $i$ 的路徑,加上從 $i$ 到 $a_i$ 的傳送,加上從 $a_i$ 到 $1$ 的路徑。而其餘的部分我們可以看作是掛在 $1 \to i$ 和 $a_i \to 1$ 這兩條鏈上的路徑。我們先考慮 $1 \to i \to a_i \to 1$ 消耗的體力。定義 $d_i$ 表示從 $1$ 到 $i$ 這條路徑上的節點數量($d_1 = 1$)。首先是 $1 \to i$,容易知道經過了 $d_i$ 個節點和 $d_i - 1$ 條邊,因此消耗的體力為 $2d_i - 1$。然後是 $i \to a_i$,使用傳送門消耗 $1$ 點體力。最後是 $a_i \to 1$,首先經過了 $d_{a_i} - 1$ 條邊,但經過的 $d_{a_i}$ 個點中 $1 \to p$($p=\mathrm{lca}(i, a_i)$)路徑上的點會被重複經過,共 $d_{p}$ 個點,因此消耗的體力應該為 $d_{a_i} - 1 + d_{a_i} - d_p$。最後總共消耗的體力就是 $s = (2d_i - 1) + (1) + (d_{a_i} - 1 + d_{a_i} - d_p) = 2d_i + 2d_{a_i} - d_p - 1$,且訪問過的節點數量為 $t = d_i + d_{a_i} - d_p$。

  將剩餘的體力記為 $r = m - s$,考慮體力 $r$ 可以訪問多少個掛在 $1 \to i$ 和 $a_i \to 1$ 這兩條鏈上的路徑的節點。和上面的分析一樣,對於每個被訪問的點 $u$,邊 $(u,p)$ 會被恰好訪問 $2$ 次,因此訪問一個點消耗的體力就是 $3$,因此最多能訪問的節點數量就是 $\min\left\{n - t, \left\lfloor \frac{r}{3} \right\rfloor \right\}$。所以如果使用第 $i$ 個傳送門,最多能訪問 $t + \min\left\{n - t, \left\lfloor \frac{r}{3} \right\rfloor \right\}$ 個節點,記為 $f_i$。

  因此最後的答案就是 $\max\left\{ \left\lfloor \frac{m+2}{3} \right\rfloor, \; \max\limits_{1 \leq i \leq n}\{f_i\} \right\}$。

  AC 程式碼如下,時間複雜度為 $O(n \log{n})$:

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

typedef long long LL;

const int N = 2e5 + 5, M = N * 2;

int a[N];
int h[N], e[M], ne[M], idx;
int fa[N][18], d[N];

void add(int u, int v) {
    e[idx] = v, ne[idx] = h[u], h[u] = idx++;
}

void dfs(int u, int p) {
    fa[u][0] = p;
    d[u] = d[p] + 1;
    for (int i = 1; i <= 17; i++) {
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    }
    for (int i = h[u]; i != -1; i = ne[i]) {
        int v = e[i];
        if (v == p) continue;
        dfs(v, u);
    }
}

int lca(int a, int b) {
    if (d[a] < d[b]) swap(a, b);
    for (int i = 17; i >= 0; i--) {
        if (d[fa[a][i]] >= d[b]) a = fa[a][i];
    }
    if (a == b) return a;
    for (int i = 17; i >= 0; i--) {
        if (fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i];
    }
    return fa[a][0];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    memset(h, -1, sizeof(h));
    for (int i = 0; i < n - 1; i++) {
        int u, v;
        cin >> u >> v;
        add(u, v), add(v, u);
    }
    dfs(1, 0);
    int ret = (m + 2) / 3;
    for (int i = 1; i <= n; i++) {
        int p = lca(i, a[i]);
        int s = 2 * d[i] + 2 * d[a[i]] - d[p] - 1;
        int t = d[i] + d[a[i]] - d[p];
        if (s <= m) ret = max(ret, t + min(n - t, (m - s) / 3));
    }
    cout << ret;
    
    return 0;
}

參考資料

  【題解】牛客小白月賽104文字題解:https://ac.nowcoder.com/discuss/1434170

相關文章