「POI 2009」救火站

题目大意:

#include <cstdio>
 
typedef long long LL;
const int N = 100005;
int head[N], nxt[N<<1], v[N<<1], n, s, k, tot;
LL a[N][25], b[N][25], tmp, ans;
 
int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x;
}
void add_edge(int from, int to) {
    nxt[++tot] = head[from];
    head[from] = tot, v[tot] = to;
}
void dfs(int u, int fa) {
    a[u][0] = 1;
    for (int i = head[u]; i; i = nxt[i]) {
        if (v[i] == fa) continue;
        dfs(v[i], u);
        for (int j = 1; j <= k; ++j) a[u][j] += a[v[i]][j-1];
        for (int j = 0; j < k; ++j) b[u][j] += b[v[i]][j+1];
    }
    tmp = (a[u][k] + s - 1) / s; //向上取整, 表示需要新增的站点数
    ans += tmp;
    b[u][k] += tmp * s;
    for (int i = 0; i <= k; ++i) {
        if (!b[u][i]) continue; //如果没有用于覆盖的则跳过
        for (int j = i; ~j && (j >= i - 1 || u == 1); --j) {
            if (b[u][i] <= a[u][j]) {
                a[u][j] -= b[u][i], b[u][i] = 0;
                break;
            }
            b[u][i] -= a[u][j], a[u][j] = 0;
        }
    }
}
 
int main() {
    n = read(), s = read(), k = read();
    for (int i = 1; i < n; ++i) {
        int u = read(), v = read();
        add_edge(u, v), add_edge(v, u);
    }
    dfs(1, 0), tmp = 0;
    for (int i = 0; i <= k; ++i) tmp += a[1][i];
    ans += (tmp + s - 1) / s;
    printf("%lld\n", ans);
    return 0;
}