Cod sursa(job #2652804)

Utilizator KPP17Popescu Paul KPP17 Data 25 septembrie 2020 20:02:51
Problema Arbore partial de cost minim Scor 20
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.43 kb

#define fisier "apm"
#include <fstream>
std::ifstream in(fisier ".in");
std::ofstream out(fisier ".out");
#define range(i, n) for (int i = 0; i < n; i++)



const int
N = 200000,
M = 2*N,
C = 1000,
INF = M*C+1;

struct Arc {int b, cost;};
struct Muchie {int a, b, cost;};
inline bool operator < (Arc& a, Arc& b) {return a.cost < b.cost;}
inline bool operator < (Muchie& a, Muchie& b) {return a.cost < b.cost;}
inline std::istream& operator >> (std::istream& in, Muchie& m) {in >> m.a >> m.b >> m.cost; m.a--, m.b--; return in;}
inline std::ostream& operator << (std::ostream& out, Muchie& m) {return out << m.a+1 << ' ' << m.b+1 << '\n';}

#include <vector>
namespace dj
{
    int set[N];

    void reset(int n)
    {range(i, n) set[i] = -1;}

    int rad(int x)
    {
        std::vector<int> drum;
        while (set[x] >= 0)
        {
            drum.push_back(x);
            x = set[x];
        }
        for (auto y: drum)
            set[y] = x;
        return x;
    }

    void uneste(int ra, int rb)
    {
        if (set[ra] > set[rb])
            std::swap(ra, rb);
        set[ra] += set[rb];
        set[rb] = ra;
    }
}

template class std::vector<int>; // Pentru depanare
template <typename Type> // Type are operatorul <
struct heap
{
    std::vector<Type> vector;

    inline Type top() // O(1)
    {return vector.front();}

    inline int _fiu0(int idx1) {return idx1 << 1;} // idx1 - Index de la 1.
    inline int _fiu1(int idx1) {return (idx1 << 1)+1;}
    inline int _tata(int idx1) {return idx1 >> 1;}

    inline int fiu0(int idx) {return _fiu0(idx+1)-1;} // idx - Index de la 0.
    inline int fiu1(int idx) {return _fiu1(idx+1)-1;}
    inline int tata(int idx) {return idx? _tata(idx+1)-1: 0;}

    void sink()
    {
        int i = 0;
        begin:
        for (int fiu: {fiu0(i), fiu1(i)})
        {
            if (fiu >= (int)vector.size())
                break;
            if (vector[fiu] < vector[i])
            {
                std::swap(vector[i], vector[fiu]);
                i = fiu;
                goto begin;
            }
        }
    }

    void rise()
    {
        int i = (int)vector.size() - 1;
        while (vector[i] < vector[tata(i)])
        {
            std::swap(vector[i], vector[tata(i)]);
            i = tata(i);
        }
    }

    void pop() // O(log vector.size())
    {
        std::swap(vector.front(), vector.back());
        vector.pop_back();
        sink();
    }

    void push(Type val) // O(log vector.size())
    {
        vector.push_back(val);
        rise();
    }
};

namespace apm // A se face dj::reset() inainte de apm::prim(...)
{
    Arc tata[N];
    int rank[N], cost;

    std::vector<Muchie> prim(std::vector<Arc>* vecini, int radacina)
    {
        heap<Muchie> inventar;
        std::vector<Muchie> muchii;
        auto adauga_vecini = [&inventar, vecini](int a)
        {
            for (auto arc: vecini[a])
                if (arc.b != a) // Optimizare minora: Nu te intoarce in arbore
                    inventar.push({a, arc.b, arc.cost});
        };
        adauga_vecini(radacina);
        while (inventar.vector.size())
        {
            Muchie muchie = inventar.top();
            inventar.pop();
            int ra = dj::rad(radacina), rb = dj::rad(muchie.b);
            if (ra != rb) // ^^^^^^^^ \\ !!! (Avem o singura componenta in arborele care se formeaza; putem folosi radacina)
            {
                dj::uneste(ra, rb); ///
                muchii.push_back(muchie);
                cost += muchie.cost;
                tata[muchie.b] = {muchie.a, muchie.cost};
                rank[muchie.b] = rank[muchie.a] + 1;
                adauga_vecini(muchie.b); ///
            }
        }
        return muchii; // Vectorul va fi un xvalue.
    }
}



std::vector<Arc> vecini[N];
int main()
{
    int n, m;
    in >> n >> m;
    while (m--)
    {
        Muchie m; // Nu va interfera cu celalalt m.
        in >> m; //  Muchia este stearsa inainte de verificarea conditiei
        vecini[m.a].push_back({m.b, m.cost});
        vecini[m.b].push_back({m.a, m.cost});
    }
    dj::reset(n);
    for (Muchie muchie: apm::prim(vecini, 0))
    {
        if (apm::cost != INF)
        {
            out << apm::cost << '\n' << n - 1 << '\n';
            apm::cost = INF;
        }
        out << muchie;
    }
}