Submission #827929

#TimeUsernameProblemLanguageResultExecution timeMemory
827929Liudas열쇠 (IOI21_keys)C++17
100 / 100
253 ms84768 KiB
#include <bits/stdc++.h>
using namespace std;

template <int maxN>
struct dsu
{
    int n, parents[maxN], rank[maxN];
    void clear(int size)
    {
        n = size;
        for (int i = 0; i < n; i++)
            parents[i] = i;
        memset(rank, 0, sizeof(int) * n);
    }
    int get(int a) { return parents[a] == a ? a : parents[a] = get(parents[a]); }
    int merge(int a, int b)
    {
        if ((a = get(a)) == (b = get(b)))
            return 0;
        if (rank[a] < rank[b])
        {
            parents[a] = b;
        }
        else
        {
            parents[b] = a;
            if (rank[a] == rank[b])
                rank[a]++;
        }
        return 1;
    }
};
dsu<300000> parent;

template <int maxN, int maxM>
struct graph
{
    struct edge;
    struct vertex
    {
        edge *next;
        int visited, r;
    } vs[maxN], *end = vs + maxN;
    struct edge
    {
        vertex *to;
        edge *next;
        int c;
    } es[maxM], *nextE = es;
    void clear(int n) { memset(vs, 0, sizeof(vertex) * n), end = vs + n, nextE = es; }
    edge *add(int from, int to) { return nextE->to = vs + to, nextE->next = vs[from].next, vs[from].next = nextE++; }

    int round, min, reachSize, ans[maxN], ansSize, key[maxN], noKey[maxM], noKeySize;
    vertex *reach[maxN];
    vector<vertex *> noKeys[maxN];
    vector<int> solve()
    {
        round = 0;
        min = 0x3f3f3f3f;
        ansSize = 0;
        parent.clear(end - vs);

        for (vertex *v = vs; v != end; v++)
        {
            for (int i = 0; i < reachSize; i++)
                key[reach[i]->r] = 0;
            for (int i = 0; i < noKeySize; i++)
                noKeys[noKey[i]].clear();
            reachSize = 0;
            noKeySize = 0;
            round++;

            if (!dfs(v, v))
            {
                if (reachSize < min)
                {
                    min = reachSize;
                    ansSize = 0;
                }
                if (reachSize == min)
                    for (int i = 0; i < reachSize; i++)
                        ans[ansSize++] = reach[i] - vs;
            }
        }

        vector<int> ret(end - vs);
        for (int i = 0; i < ansSize; i++)
            ret[ans[i]] = 1;
        return ret;
    }
    int dfs(vertex *v, vertex *start)
    {
        if (reachSize == min)
            return 1;
        reach[reachSize++] = v;

        v->visited = round;
        if (parent.merge(start - vs, v - vs))
            return 1;

        if (!key[v->r])
        {
            key[v->r] = 1;
            for (vertex *u : noKeys[v->r])
                if (u->visited < round)
                    if (dfs(u, start))
                        return 1;
        }

        for (edge *e = v->next; e; e = e->next)
            if (e->to->visited < round)
            {
                if (key[e->c])
                {
                    if (dfs(e->to, start))
                        return 1;
                }
                else
                {
                    noKey[noKeySize++] = e->c;
                    noKeys[e->c].push_back(e->to);
                }
            }
        return 0;
    }
};
graph<300000, 2 * 300000> g;

vector<int> find_reachable(vector<int> r, vector<int> u, vector<int> v, vector<int> c)
{
    int n = r.size(), m = u.size();
    g.clear(n);

    for (int i = 0; i < n; i++)
        g.vs[i].r = r[i];
    for (int i = 0; i < m; i++)
    {
        g.add(u[i], v[i])->c = c[i];
        g.add(v[i], u[i])->c = c[i];
    }

    return g.solve();
}

void testCase()
{
    int n, m;
    cin >> n >> m;
    vector<int> r(n);
    for (int i = 0; i < n; i++)
        cin >> r[i];

    vector<int> u(m), v(m), c(m);
    for (int i = 0; i < m; i++)
        cin >> u[i] >> v[i] >> c[i];

    auto ans = find_reachable(r, u, v, c);
    for (auto v : ans)
        cout << v << ' ';
}

/*int main()
{
    testCase();
    return 0;
}*/
#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...