Cod sursa(job #2652401)

Utilizator KPP17Popescu Paul KPP17 Data 24 septembrie 2020 20:39:31
Problema Lazy Scor 50
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.32 kb

#define fisier "lazy"
#include <fstream>
std::ifstream in(fisier ".in");
std::ofstream out(fisier ".out");

#define range(i, n) for (int i = 0; i < n; i++)
#define iter(i, v) for (auto i: v)



const int
N = 200000,
M = N;

struct Arc {int b, c1, c2;};
struct Muchie {int a, b, c1, c2;};

std::ostream& operator << (std::ostream& stream, Muchie& muchie)
{return stream << muchie.a+1 << ' ' << muchie.b+1 << '\n';}
std::istream& operator >> (std::istream& stream, Muchie& muchie)
{stream >> muchie.a >> muchie.b >> muchie.c1 >> muchie.c2; muchie.a--, muchie.b--; return stream;}

int n;



#include <vector>
namespace disjunct
{
    int _set[N];

    void reset(int* set = _set) // O(n) // A se apela inainte de utilizare, ca de nu esti mort.
    {range (i, n) set[i] = -1;}

    int rad(int x, int* set = _set) // O(log n) sau O(1).
    {
        std::vector<int> drum;
        while (set[x] >= 0)
        {
            drum.push_back(x);
            x = set[x];
        }
        iter (y, drum) // Compresie de drum pentru O(1).
            set[y] = x;
        return x;
    }

    void uneste(int rad_a, int rad_b, int* set = _set) // O(1)
    {
        if (set[rad_a] > set[rad_b]) // Daca a are mai putine.
            std::swap(rad_a, rad_b);
        set[rad_a] += set[rad_b];
        set[rad_b] = rad_a;
    }
}

template class std::vector<Muchie>; // Pentru depanarea vectorilor in GDB.
template class std::vector<int>;
std::vector<Muchie> _muchii;
std::vector<int> muchii; // Indici.

#include <queue>
namespace apm
{
    Arc tata[N];
    int rank[N];

    void reset() // O(n)
    {range(i, n) {tata[i].b = -1; rank[i] = 0;}}

    void kruskal(std::vector<int>& muchii, int* set = disjunct::_set, void (*functie)(int) = NULL, int limita = n - 1) // O(m log m)
    {
        iter (idx, muchii)
        {
            Muchie muchie = _muchii[idx];
            if (!limita)
                break;

            int
            rad_a = disjunct::rad(muchie.a, set), // O(log n)
            rad_b = disjunct::rad(muchie.b, set); // O(log n)

            if (rad_a != rad_b)
            {
                disjunct::uneste(rad_a, rad_b, set); // O(1)
                functie(idx);
                limita--;
            }
        }
    }
}



#include <algorithm>
int main()
{
    int m;
    in >> n >> m;

    _muchii.reserve(m); // Optimizare minora.
    muchii.reserve(m);

    while (m--)
    {
        Muchie muchie;
        in >> muchie;
        _muchii.push_back(muchie);
    }

    range(i, _muchii.size())
        muchii.push_back(i);

    std::sort(muchii.begin(), muchii.end(),
    [](int a, int b) {return _muchii[a].c1 < _muchii[b].c1;});

    range(j, muchii.size()) // Voi itera manual prin indici,
    {                       // din cauza comportamentului neasteptat al iteratorilor in sortare.
        int i = j;
        while (j < muchii.size() - 1 && _muchii[muchii[i]].c1 == _muchii[muchii[j+1]].c1) // In loc sa pun c1 am pus c2 - greseala stupida
            j++;
        std::sort(muchii.begin() + i, muchii.begin() + j+1,
        [](int a, int b) {return _muchii[a].c2 > _muchii[b].c2;});
    }

    disjunct::reset();
    apm::reset();
    apm::kruskal(muchii, disjunct::_set, [](int idx) {out << idx+1 << '\n';});
}