[건설] [DFS 트리] [LOJ # 3176] [트리의 중심] "IOI2019"분할 관광 명소

  • 주제 포털

  • 이제 가정하자 \ (A \ 르 B \ 르 C를 \) , 우리는 지속적으로 더 작은 통신 블록을 결과 점을 천공 통신 블록에서 할 수 있습니다, 그것은 제국의 크기에 가능하다 \ (A \)\ (B \) 의 세트 포인트가 연결된

  • 이 크기 때문에 \ (A \)(B \) \ 두 블록 확인 통신 후, 우리는 필연적으로 세트가 모두 포함이 두 지점 확장이 두 블록 통신을 만들 것입니다 \ (N- \) 일을 점은, 문제는 통신의 두 블록, 최소의 크기로 원 화상으로 변환되고, \ (a \) , 적어도 크기 \ (B \)

  • 즉, 두 블록의 크기에 부합해야하는 통신 중 어느으로부터 선택 \ ([A (NB)] \ ) 또는 내부 (\ [노나, B]를 \ ) 내부. 상기 조건은 통신 블록 조건이 만족되지 않는 것을 특징으로 만족 블록 통신 방법이면 정당한 아니다

  • 분할 블록의 측면이 직접 통신 출력 응답의 조건을 만족하는 경우 Xianpao 다시 DFS 트리 트리 각 측면을 열거

  • 그렇지 않으면, DFS 트리의 무게 중심을 고려하십시오. 각 서브 트리의 무게 중심의 사이즈에 주목하는 것은 아닌 ([A (NB)] \ \ ) 내에 (또는 그 이전에 유효한 것으로 판정 된 경우), 그리고 \ (A + B + C = n \) 와 \ (a \ 르 B \ 르 C \) 이므로 \ (B \ 르 \ FRAC N2 \) 의 무게 중심 (이들 각각은 서브 트리의 크기를 초과하지 않는의 특성상, \ (\ FRAC N2 \) 각각의 서브 트리의 크기의 중심을 구하기 위하여는)이다 <(\ \)

  • 각 하위 트리의 무게 중심을 고려하십시오. 트리 내의 자식 해 버리는 측면 (중력 자체의 중심을 포함하지 않음) 조상의 중심에 접속되어 있지 않은 경우,이 확실히 트리의 서브 트리를하지 것 (불가피 같은 통신 블록에 속하는 중심 서브 트리 여기서 상기 통신 블록 크기 \ (\ GE A를 \) )

  • 이러한 모든 서브 트리 및 중력의 통신 블록 합성 블록의 통신의 크기보다 큰 경우 \ (NA \) 해결책

  • 그렇지 않으면, 초기 용액의 구성, 서브 - 트리에서의 무게 중심 (\ B) \ 세트, 나머지가 배치 \ (A \) 집합

  • 물론, 상기 서브 트리의 무게 중심의 크기 이상이고 \ (NA \) 이다 (그 때문에 덩어리 크기가 상기 중심 \ (<A \) )

  • 모든 무게 중심을 이동 중력 조상 선조의 서브 트리의 중심의 복귀 측 접속 차례로이 (A \) \ 까지 집합 내 \ (B \) 세트의 크기 \ (\ 르 NA \) 까지

  • 어떻게 이런 일이 얻을 증명하기 위해 \ (B \) 콜렉션의 크기를 \ (\ GE의 B를 \) ?

  • 증명 : 서로 가입일 \ (B \) 임의의 서브 트리의 크기의 컬렉션 삭제 \ (<A를 \)\ (a \ 르 B \ 르 C \) 보장하지만 \ (a \ 르 \ FRAC N3 \) 및 \ (C \ GE \ FRAC N3 \) 와 간격 \ ([B, NA는] \ ) 의 크기 \ (C +. 1 \) 이므로 \ (a \)의 간격보다 작아야 \ ([B, NA] \) 의 크기, 그 수단 \ (B \) 컬렉션 크기 \ (> NA \) 의 경우, 서브 - 트리 번 못하게 삭제없이 (B \) \ 컬렉션 크기가된다 (\ <B를 \) , 입증

  • \ (O (N + m) \)

암호

#include <bits/stdc++.h>

template <class T>
inline void read(T &res)
{
    res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    if (bo) res = ~res + 1;
}

template <class T>
inline T Max(const T &a, const T &b) {return a > b ? a : b;}

template <class T>
inline T Min(const T &a, const T &b) {return a < b ? a : b;}

const int N = 1e5 + 5, M = 4e5 + 5;

int n, m, a, b, c, ecnt, nxt[M], adj[N], sze[N], maxs[N], go[M], tr[4],
dep[N], ans[N], G = 1;
bool vis[N], ind[N];

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

void add_edge(int u, int v)
{
    nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
    nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u;
}

void dfs(int u)
{
    vis[u] = 1; sze[u] = 1;
    for (int e = adj[u], v; e; e = nxt[e])
        if (!vis[v = go[e]])
        {
            dep[v] = dep[u] + 1; dfs(v); sze[u] += sze[v];
            maxs[u] = Max(maxs[u], sze[v]);
            son[u].push_back(v);
        }
}

int calc(int u)
{
    int res = n + 1;
    for (int e = adj[u], v = go[e]; e; e = nxt[e], v = go[e])
        res = Min(res, dep[v]);
    for (int i = 0; i < son[u].size(); i++)
        res = Min(res, calc(son[u][i]));
    return res;
}

void setr(int u, int c)
{
    ans[u] = c;
    for (int i = 0; i < son[u].size(); i++)
        setr(son[u][i], c);
}

void other(int c)
{
    for (int u = 1; u <= n; u++) if (!ans[u]) ans[u] = c;
}

void fake(int u, int s)
{
    vis[u] = 1; sze[u] = 1;
    for (int e = adj[u], v; e; e = nxt[e])
        if (!vis[v = go[e]] && ans[u] == ans[v])
        {
            fake(v, s); sze[u] += sze[v];
            if (s <= sze[v]) return;
            s -= sze[v];
        }
    if (s) ans[u] = 3;
}

void output(int ca, int cb)
{
    memset(vis, 0, sizeof(vis));
    for (int u = 1; u <= n; u++)
        if (ans[u] == 1) {fake(u, ca - a); break;}
    for (int u = 1; u <= n; u++)
        if (ans[u] == 2) {fake(u, cb - b); break;}
    for (int u = 1; u <= n; u++) printf("%d ", tr[ans[u]]);
    puts(""); exit(0);
}

int main()
{
    int x, y;
    read(n); read(m); read(a); read(b); read(c);
    tr[1] = 1; tr[2] = 2; tr[3] = 3;
    if (a > b) std::swap(a, b), std::swap(tr[1], tr[2]);
    if (a > c) std::swap(a, c), std::swap(tr[1], tr[3]);
    if (b > c) std::swap(b, c), std::swap(tr[2], tr[3]);
    while (m--) read(x), read(y), add_edge(x + 1, y + 1);
    dfs(dep[1] = 1);
    for (int u = 2; u <= n; u++)
    {
        if (a <= sze[u] && sze[u] <= n - b)
            setr(u, 1), other(2), output(sze[u], n - sze[u]);
        if (b <= sze[u] && sze[u] <= n - a)
            setr(u, 2), other(1), output(n - sze[u], sze[u]);
    }
    for (int u = 2; u <= n; u++)
        if (Max(maxs[u], n - sze[u]) < Max(maxs[G], n - sze[G]))
            G = u;
    int sum = 1;
    for (int i = 0; i < son[G].size(); i++)
        if (ind[i] = calc(son[G][i]) >= dep[G]) sum += sze[son[G][i]];
    if (sum > n - a) output(0, 0);
    setr(G, 2); other(1); sum = sze[G];
    for (int i = 0; i < son[G].size(); i++)
        if (!ind[i] && sum > n - a) sum -= sze[son[G][i]], setr(son[G][i], 1);
    return output(n - sum, sum), 0;
}

추천

출처www.cnblogs.com/xyz32768/p/12333627.html