BZOJ 1086: [SCOI2005]王室联邦

w..学树上莫队的时候回来做了这道题,好久没有这么快地A过题了……

dfs保证相邻的节点在同一个块内,只要当前子树的大小大于等于 B ,就将它们分到一个块里,选当前节点为省会,最后有可能会剩下一部分到根的节点不足 B 个,将它们随便分到一个之前的块里就可以。因为剩下的节点数目 < B ,任意一个块的大小 < 2 B ,它们加起来一定 < 3 B

#include <cstdio>
#include <vector>

const int N = 1005;

std::vector<int> G[N];

int sta[N], top, be[N], root[N], n, b, cnt;

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 dfs(int u, int fa) {
    int sz = G[u].size(), now = top;
    for (int i = 0; i < sz; ++i) {
        int v = G[u][i];
        if (v == fa) continue;
        dfs(v, u);
        if (top - now >= b) {
            root[++cnt] = u;
            while (top > now) be[sta[top--]] = cnt;
        }
    }
    sta[++top] = u;
}

int main() {
    n = read(), b = read();
    for (int i = 1; i < n; ++i) {
        int u = read(), v = read();
        G[u].push_back(v), G[v].push_back(u);
    }
    dfs(1, 0);
    while (top) be[sta[top--]] = cnt;
    printf("%d\n", cnt);
    for (int i = 1; i <= n; ++i) printf("%d ", be[i]); puts("");
    for (int i = 1; i <= cnt; ++i) printf("%d ", root[i]); puts("");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/milkyyyyy/article/details/81146578