제출 #1317817

#제출 시각아이디문제언어결과실행 시간메모리
1317817spetr스핑크스 (IOI24_sphinx)C++20
0 / 100
0 ms332 KiB
#include <bits/stdc++.h>
#include "sphinx.h"
using namespace std;

std::vector<int> find_colours(int N, std::vector<int> X, std::vector<int> Y) {
    int n = N;
    vector<vector<int>> adj(n);
    for (size_t i = 0; i < X.size(); i++) {
        adj[X[i]].push_back(Y[i]);
        adj[Y[i]].push_back(X[i]);
    }

    // 1. Vybudování BFS stromu pro získání rodičů a hloubek
    vector<int> parent(n, -1);
    vector<int> depth(n, 0);
    vector<int> bfs_order;
    vector<bool> vis(n, false);
    
    queue<int> q;
    q.push(0);
    vis[0] = true;
    
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        bfs_order.push_back(u);
        
        for (int v : adj[u]) {
            if (!vis[v]) {
                vis[v] = true;
                parent[v] = u;
                depth[v] = depth[u] + 1;
                q.push(v);
            }
        }
    }

    vector<int> colors(n, -1);
    vector<int> a(n);
    int identified_count = 0;

    // 2. Hlavní smyčka přes možné barvy
    // Hledáme barvy pro všechny vrcholy kromě kořene (ten nemá rodiče)
    for (int c = 0; c < n; c++) {
        // Pokud jsme našli barvy pro všechny vrcholy (kromě rootu, ten řešíme na konci), končíme
        if (identified_count >= n - 1) break;

        // Rozdělíme zpracování na 3 fáze podle hloubky, abychom předešli kolizím parent-child
        for (int rem = 0; rem < 3; rem++) {
            
            // Helper: Zjistí počet shod v podmnožině kandidátů
            auto count_matches = [&](const vector<int>& candidates, int l, int r) {
                if (l > r) return 0;

                // Reset: nastavíme vše na 'n' (neutrální hodnota)
                fill(a.begin(), a.end(), n);
                
                int active_pairs = 0;
                for (int i = l; i <= r; i++) {
                    int u = candidates[i];
                    int p = parent[u];
                    // u nastavíme na wildcard (-1)
                    // rodiče p nastavíme na cílovou barvu c
                    a[u] = -1;
                    a[p] = c; 
                    // Poznámka: Jeden rodič může obsloužit více dětí najednou, to je v pořádku.
                    // Pokud se u a p spojí, ubyde jedna komponenta.
                }

                // Pokud jsme nic nenastavili, vracíme 0
                // Musíme spočítat, kolik vrcholů jsme reálně 'aktivovali' (nastavili na -1)
                // Protože 'active_pairs' výše jen nastavuje pole, spočteme si reálný počet unikátních aktivací
                int nodes_involved = 0;
                for (int i = l; i <= r; i++) { 
                    nodes_involved++; 
                    // Komponenta navíc vznikne jen pokud se nespojí.
                    // Očekávaný počet komponent pro tyto páry, pokud by se nic nespojilo, je nodes_involved (každý u je sám, p je buď sám nebo s jinými).
                    // Ale pozor: perform_experiment vrací celkový počet komponent v grafu.
                    // Musíme porovnat s "base line".
                }
                
                if (nodes_involved == 0) return 0;

                int components = perform_experiment(a);
                // Každý úspěšný match (u má barvu c) sníží počet komponent o 1 oproti stavu, kdyby match nebyl.
                // Celkový počet vrcholů je n.
                // Počet komponent = n - (počet úspěšných spojení).
                // Toto platí, protože u je list (v našem experimentálním podgrafu, u má jen hranu na p).
                return n - components;
            };

            // Smyčka pro nalezení všech výskytů barvy v aktuální vrstvě
            while (true) {
                // Vybereme kandidáty: neobarvené vrcholy v této vrstvě (kromě rootu)
                vector<int> candidates;
                for (int u : bfs_order) {
                    if (u != 0 && colors[u] == -1 && depth[u] % 3 == rem) {
                        candidates.push_back(u);
                    }
                }

                if (candidates.empty()) break;

                // Rychlá kontrola celé skupiny
                int total = count_matches(candidates, 0, candidates.size() - 1);
                if (total == 0) break; // Žádný další vrchol v této vrstvě nemá barvu c

                // Binary search pro nalezení konkrétního vrcholu
                int l = 0, r = candidates.size() - 1;
                int found_idx = -1;

                while (l <= r) {
                    if (l == r) {
                        found_idx = l;
                        break;
                    }
                    int mid = l + (r - l) / 2;
                    if (count_matches(candidates, l, mid) > 0) {
                        r = mid;
                    } else {
                        l = mid + 1;
                    }
                }

                if (found_idx != -1) {
                    int u = candidates[found_idx];
                    colors[u] = c;
                    identified_count++;
                    // Pokračujeme v cyklu while(true), abychom našli další případné vrcholy stejné barvy ve stejné vrstvě
                } else {
                    break;
                }
            }
        }
    }

    // 3. Dořešení kořene (vrchol 0)
    // Kořen nemá rodiče, musíme ho porovnat s jeho sousedy, kteří už barvu mají.
    if (colors[0] == -1) {
        // Zkusíme, zda kořen nemá stejnou barvu jako některý z jeho sousedů
        // Iterujeme přes možné barvy c
        for (int c = 0; c < n; c++) {
            // Má kořen souseda s barvou c?
            bool has_neighbor_c = false;
            for (int v : adj[0]) {
                if (colors[v] == c) {
                    has_neighbor_c = true;
                    break;
                }
            }
            
            if (has_neighbor_c) {
                fill(a.begin(), a.end(), n);
                a[0] = -1;
                // Nastavíme všechny sousedy barvy c na c
                for (int v : adj[0]) {
                    if (colors[v] == c) a[v] = c;
                }
                
                if (perform_experiment(a) < n) {
                    colors[0] = c;
                    break;
                }
            }
        }
        
        // Pokud jsme nenašli shodu s žádným sousedem, dáme mu první volnou barvu
        // (Většinou to bude barva, kterou cyklus výše nenašel, protože kořen byl jediný svého druhu nebo izolovaný v barvě)
        if (colors[0] == -1) {
            // Najdeme nejmenší nepoužitou barvu v okolí? Ne, prostě přiřadíme novou.
            // Ale musíme dodržet konzistenci, zkusíme najít první c, které jsme v grafu použili, nebo prostě volnou.
            // Nejbezpečnější je nechat ho být, pokud úloha vyžaduje jen partition,
            // ale my vracíme konkrétní čísla. Najdeme první nepoužité C?
            // V zadání Sphinx se obvykle vrací IDs. Pokud je root unikátní, může mít jakékoliv ID.
            // Pro jistotu mu dáme nějakou bezpečnou barvu (např. max_used + 1 nebo jen 0 pokud je vše 0).
            int max_c = -1;
            for(int x : colors) max_c = max(max_c, x);
            colors[0] = max_c + 1;
        }
    }

    // Fallback pro jistotu
    for (int i = 0; i < n; i++) {
        if (colors[i] == -1) colors[i] = 0;
    }

    return colors;
}
#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...
#Verdict Execution timeMemoryGrader output
Fetching results...