제출 #691035

#제출 시각아이디문제언어결과실행 시간메모리
691035finn__Split the Attractions (IOI19_split)C++17
0 / 100
1 ms340 KiB
#include <bits/stdc++.h>
#include "split.h"
using namespace std;

vector<vector<unsigned>> g;
vector<unsigned> preoder, postorder, subtree_size;
vector<bool> has_backward_edge;

bool is_in_subtree(unsigned u, unsigned v)
{
    return preoder[u] < preoder[v] && postorder[u] > postorder[v];
}

pair<unsigned, unsigned> traverse(
    unsigned u, vector<bool> &visited, unsigned i = 0, unsigned j = 0)
{
    preoder[u] = i++;
    visited[u] = 1;
    subtree_size[u] = 1;

    for (unsigned const &v : g[u])
        if (!visited[v])
        {
            tie(i, j) = traverse(v, visited, i, j);
            subtree_size[u] += subtree_size[v];
        }

    postorder[u] = j++;
    return {i, j};
}

void find_backward_edges(unsigned u, vector<bool> &visited)
{
    visited[u] = 1;

    for (unsigned const &v : g[u])
    {
        if (!visited[v])
            find_backward_edges(v, visited);
        else if (!is_in_subtree(u, v))
            has_backward_edge[u] = 1;
    }
}

unsigned find_split_node(unsigned u, vector<bool> &visited, unsigned a)
{
    visited[u] = 1;
    unsigned curr_size = subtree_size[u];
    bool is_min_greater = 1;

    for (unsigned const &v : g[u])
        if (!visited[v] && subtree_size[v] >= a)
            is_min_greater = 0;

    if (is_min_greater)
        for (unsigned const &v : g[u])
        {
            if (!visited[v])
            {
                if (curr_size - subtree_size[v] < a)
                    return u;
                if (has_backward_edge[v])
                    curr_size -= subtree_size[v];
            }
        }

    for (unsigned const &v : g[u])
    {
        if (!visited[v])
        {
            unsigned x = find_split_node(v, visited, a);
            if (x != UINT_MAX)
                return x;
        }
    }

    return UINT_MAX;
}

unsigned dfs_down(
    unsigned u, vector<bool> &visited, vector<int> &ans, unsigned to_add,
    unsigned added_size, unsigned z1, unsigned z2)
{
    visited[u] = 1;
    if (added_size < to_add)
    {
        ans[u] = z1;
        added_size++;
    }
    else
        ans[u] = z2;

    for (unsigned const &v : g[u])
    {
        if (!visited[v] && is_in_subtree(u, v))
            added_size = dfs_down(v, visited, ans, to_add, added_size, z1, z2);
    }

    return added_size;
}

unsigned dfs_up(
    unsigned u, vector<bool> &visited, vector<int> &ans, unsigned to_add,
    unsigned added_size, unsigned z1, unsigned z2)
{
    visited[u] = 1;
    if (added_size < to_add)
    {
        ans[u] = z1;
        added_size++;
    }
    else
        ans[u] = z2;

    for (unsigned const &v : g[u])
    {
        if (!visited[v])
            added_size = dfs_up(v, visited, ans, to_add, added_size, z1, z2);
    }

    return added_size;
}

vector<int> find_split(int n, int a, int b, int c, vector<int> p, vector<int> q)
{
    array<pair<unsigned, unsigned>, 3> y;
    y[0] = {a, 1}, y[1] = {b, 2}, y[2] = {c, 3};
    sort(y.begin(), y.end());

    g = vector<vector<unsigned>>(n);
    preoder = vector<unsigned>(n);
    postorder = vector<unsigned>(n);
    subtree_size = vector<unsigned>(n);

    for (size_t i = 0; i < p.size(); i++)
    {
        g[p[i]].push_back(q[i]);
        g[q[i]].push_back(p[i]);
    }

    vector<bool> visited(n, 0);
    traverse(0, visited);
    fill(visited.begin(), visited.end(), 0);

    has_backward_edge = vector<bool>(n, 0);
    find_backward_edges(0, visited);
    fill(visited.begin(), visited.end(), 0);

    unsigned x = find_split_node(0, visited, y[0].first);
    if (x == UINT_MAX)
        return vector<int>(n, 0);
    else
    {
        fill(visited.begin(), visited.end(), 0);
        unsigned p = UINT_MAX;
        for (unsigned const &v : g[x])
            if (!is_in_subtree(x, v))
            {
                p = v;
                break;
            }
        vector<int> ans(n);
        dfs_down(x, visited, ans, subtree_size[x] >= y[1].first ? y[1].first : y[0].first, 0,
                 subtree_size[x] >= y[1].first ? y[1].second : y[0].second,
                 y[2].second);
        dfs_up(p, visited, ans, subtree_size[x] >= y[1].first ? y[0].first : y[1].first, 0,
               subtree_size[x] >= y[1].first ? y[0].second : y[1].second,
               y[2].second);

        return ans;
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...