Submission #680336

#TimeUsernameProblemLanguageResultExecution timeMemory
680336DennisTranKeys (IOI21_keys)C++17
100 / 100
709 ms44568 KiB
#include <bits/stdc++.h>
using namespace std;

// randomized
const int n_max = 300500;

int visited_list[n_max];
bool has_key[n_max];
bool visited[n_max];
int homekey[n_max];
int a[n_max];
pair<int,int> adj[2*n_max];
pair<int,int>* z[n_max];
bool finished[n_max];

// essentially, this stores the blocked position
// vector<int> blocked[max_keys] with push/pop is too slow
// we need to manage this ourself instead of relying on library
int blocked_counter[n_max];
int blocked3[n_max]; // stores the actual values
int* blocked2[n_max]; // stores pointers


int s = 1e6;
int counter = 0;

void cleanup() {
    for(int j=0; j<counter; j++) {
        int i = visited_list[j];
        visited[i] = false;
        has_key[homekey[i]] = false;
        for(pair<int,int>* p = z[i]; p<z[i+1]; p++) {
            blocked_counter[p->first] = 0;
        }
    }
}

int dfs_stack[n_max];
int explore(int x) { // returns min(limit, size of component)
    int* pt = dfs_stack;
    *pt = x;
    pt++; // stack always points to 1 higher
    counter = 1;
    visited_list[0] = x;

    visited[x] = true;
    while(pt > dfs_stack) {
        if(counter>s) {
            return 1e6;
        }
        pt--; // pop item
        int next = *pt;

        if(!has_key[homekey[next]]) {
            has_key[homekey[next]] = true;
            for(int j=0; j<blocked_counter[homekey[next]]; j++) {
                int i = blocked2[homekey[next]][j];
                if(!visited[i]) {
                    if(finished[i] || a[i]!=a[x]) {
                        return 1e6;
                    }
                    visited[i] = true;
                    visited_list[counter] = i;
                    counter++;
                    *pt = i; // push item
                    pt++;
                }
            }
            blocked_counter[homekey[next]] = 0;
        }
        for(pair<int,int>* p = z[next]; p<z[next+1]; p++) {
            //assert(p<z[next+1]);
            if(visited[p->second]) continue;
            // we can effectively delete edges that go to a bigger component
            // if you cant use this edge eventually, good
            // else, you use this edge eventually
            // but this means we must have came from a different component
            // in which answer is not optimal anyway
            // we can pretend this edge does not exist(!)
            if(a[p->second] > a[x]) continue;
            if(has_key[p->first]) {
                if(finished[p->second] || a[p->second] != a[x]) {
                    return 1e6;
                }
                visited_list[counter] = p->second;
                visited[p->second] = true;

                counter++;
                *pt = p->second; // push item
                pt++;
            } else {
                blocked2[p->first][blocked_counter[p->first]] = p->second;
                blocked_counter[p->first]++;
            }
        }
    }
    for(int* p=visited_list; p<visited_list+counter; p++) {
        int i = *p;
        a[i] = min(a[i], counter);
    }
    return counter;
}

tuple<int,int,int> t[2*n_max];
vector<int> find_reachable(vector<int> r, vector<int> u, vector<int> v, vector<int> c) {
    int m = c.size();
    int n = r.size();
    for(int i=0; i<n; i++) {
        a[i] = 1e6;
    }

    for(int i=0; i<m; i++) {
        //adj[u[i]].emplace_back(c[i], v[i]);
        //adj[v[i]].emplace_back(c[i], u[i]);
        blocked_counter[c[i]]++;
        t[2*i] = make_tuple(u[i], v[i], c[i]);
        t[2*i+1] = make_tuple(v[i], u[i], c[i]);
    }
    sort(t, t+2*m);
    z[0] = adj;
    for(int i=0; i<2*m; i++) {
        adj[i] = make_pair(get<2>(t[i]), get<1>(t[i]));
        if(i!=0 && get<0>(t[i])!=get<0>(t[i-1])) {
            for(int j=get<0>(t[i-1])+1; j<=get<0>(t[i]); j++) {
                z[j] = adj + i;
            }
        }
    }
    z[get<0>(t[2*m-1])+1] = adj + 2*m;

    blocked2[0] = blocked3;
    for(int i=1; i<n_max; i++) {
        blocked2[i] = blocked2[i-1] + blocked_counter[i-1];
    }
    for(int i=0; i<n_max; i++) {
        blocked_counter[i] = 0;
    }
    for(int i=0; i<n; i++) {
        homekey[i] = r[i];
    }
    vector<int> p(2*m);
    for(int i=0; i<m; i++) {
        p[2*i] = u[i];
        p[2*i+1] = v[i];
    }

    random_shuffle(p.begin(), p.end());
    for(int i: p) {
        if(!finished[i]) {
            s = min(s, explore(i));
            finished[i] = true;
            cleanup();
        }
    }
    for(int i=0; i<n; i++) {
        if(!finished[i]) {
            s = min(s, explore(i));
            finished[i] = true;
            cleanup();
        }
    }

    vector<int> ans(n);
    for(int i=0; i<n; i++) {
        if(a[i]==s) {
            ans[i] = 1;
        }
    }
    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...