Submission #85073

#TimeUsernameProblemLanguageResultExecution timeMemory
85073AdrienVannsonPort Facility (JOI17_port_facility)C++17
78 / 100
152 ms52832 KiB
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <vector>
#include <set>
#include <stack>

using namespace std;

const int oo = 1000*1000*1000;

const int INCONNU = -1;
const int MODULO = 1000*1000*1000+7;

const int NB_MAX_OBJETS = 100*1000;

template<int NB_NOEUDS>
class UnionFind
{
public:

    UnionFind ()
    {
        for (int iNoeud=0; iNoeud<NB_NOEUDS; iNoeud++) {
            representants[iNoeud] = iNoeud;
            tailles[iNoeud] = 1;
        }
    }

    int representant (const int iNoeud)
    {
        if (representants[iNoeud] == iNoeud) {
            return iNoeud;
        }
        return representants[iNoeud] = representant(representants[iNoeud]);
    }

    int taille (const int iNoeud)
    {
        return tailles[representant(iNoeud)];
    }

    void unir (int iNoeud1, int iNoeud2)
    {
        iNoeud1 = representant(iNoeud1);
        iNoeud2 = representant(iNoeud2);

        if (iNoeud1 == iNoeud2) {
            return;
        }

        if (tailles[iNoeud2] > tailles[iNoeud1]) {
            swap(iNoeud1, iNoeud2);
        }

        tailles[iNoeud1] += tailles[iNoeud2];
        tailles[iNoeud2] = 0;

        representants[iNoeud2] = iNoeud1;
    }

private:
    int representants[NB_NOEUDS];
    int tailles[NB_NOEUDS]; // Valide uniquement pour les racines
};


struct Intervalle
{
    int debut, fin;

    int taille () const
    {
        return fin - debut;
    }

    bool estInclusDans (const Intervalle &autre) const
    {
        return debut >= autre.debut && fin <= autre.fin;
    }

    bool operator< (const Intervalle &autre) const
    {
        if (debut != autre.debut) {
            return debut < autre.debut;
        }
        return fin < autre.fin;
    }
};

Intervalle getUnion (const Intervalle &a, const Intervalle &b)
{
    return Intervalle {min(a.debut, b.debut), max(a.fin, b.fin)};
}

Intervalle getIntersection (const Intervalle &a, const Intervalle &b)
{
    return Intervalle {max(a.debut, b.debut), min(a.fin, b.fin)};
}

bool getAIntersection (const Intervalle &a, const Intervalle &b)
{
    return (a.debut < b.debut && a.fin > b.debut && a.fin < b.fin)
        || (b.debut < a.debut && b.fin > a.debut && b.fin < a.fin);
}


int nbObjets;
Intervalle intervalles[NB_MAX_OBJETS];

UnionFind<2*NB_MAX_OBJETS> unionFind; // Maintient les états équivalents


/*
 * Calcul de la solution optimale
 */

int getPuissance (const int puissance)
{
    int res = 1;

    for (int iPuissance=0; iPuissance<puissance; iPuissance++) {
        res = (res*2) % MODULO;
    }

    return res;
}

int getNbPossibilites ()
{
    sort(intervalles, intervalles+nbObjets, [](const Intervalle &a, const Intervalle &b) {
        return a.fin < b.fin;
    });

    set<Intervalle> pointsRestants;
    for (int iPoint=0; iPoint<nbObjets; iPoint++) {
        pointsRestants.insert(intervalles[iPoint]);
    }

    // Tous les intervalles stockés sont disjoints et représentent une composante connexe
    set< pair<Intervalle, int> > enCours; // {intervalle, etat}
    int nbComposantes = 0;


    for (int iPoint=0; iPoint<nbObjets; iPoint++) {
        pointsRestants.erase(intervalles[iPoint]);

        Intervalle actuel = intervalles[iPoint];
        int etatActuel = 2*iPoint;
        nbComposantes++;


        set<pair<Intervalle, int>>::iterator enContact = enCours.upper_bound( make_pair(actuel, etatActuel) );

        // Vérifier le contact à gauche
        if (enContact != enCours.begin()) {
            enContact--;

            if (enContact->first.fin > actuel.debut) { // Il y a une intersection

                const Intervalle intersection = getIntersection(actuel, enContact->first);

                if (pointsRestants.lower_bound(intersection) != pointsRestants.end()
                 && pointsRestants.lower_bound(intersection)->debut < intersection.fin) { // Impossible

                    return 0;
                }
                else {
                    etatActuel = unionFind.representant(enContact->second ^ 1);
                    nbComposantes--;

                    actuel.debut = enContact->first.fin;

                    if (actuel.taille() <= 0) {
                        continue;
                    }
                }
            }
        }

        // Inclusions ou contact à droite
        enContact = enCours.lower_bound( make_pair(actuel, etatActuel) );

        while (enContact != enCours.end() && enContact->first.debut < actuel.fin) { // Il y a une intersection

            const Intervalle intersection = getIntersection(actuel, enContact->first);
            const Intervalle reunion = getUnion(actuel, enContact->first);
            const int autreEtat = enContact->second;

            if (pointsRestants.lower_bound(intersection) != pointsRestants.end()
             && pointsRestants.lower_bound(intersection)->debut < intersection.fin) { // Fusionner

                if (unionFind.representant(etatActuel) == (unionFind.representant(autreEtat) ^ 1)) {
                    return 0;
                }

                // Marquer les deux états équivalents
                if (unionFind.representant(etatActuel) != unionFind.representant(autreEtat)) {
                    unionFind.unir(etatActuel, autreEtat);
                    unionFind.unir(etatActuel^1, autreEtat^1);
                    nbComposantes--;
                }

                enCours.erase(enContact);
                actuel = reunion;
            }
            else {
                if (enContact->first.fin > actuel.fin) {
                    actuel.fin = enContact->first.debut;
                }
                else {
                    enCours.erase(enContact);
                }
            }

            enContact = enCours.lower_bound(make_pair(actuel, etatActuel));
        }

        enCours.insert( make_pair(actuel, etatActuel) );
    }

    return getPuissance(nbComposantes);
}


int main ()
{
    scanf("%d", &nbObjets);

    for (int iObjet=0; iObjet<nbObjets; iObjet++) {
        scanf("%d %d", &intervalles[iObjet].debut, &intervalles[iObjet].fin);
    }

    printf("%d\n", getNbPossibilites());

    return 0;
}

Compilation message (stderr)

port_facility.cpp: In function 'int main()':
port_facility.cpp:228:10: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
     scanf("%d", &nbObjets);
     ~~~~~^~~~~~~~~~~~~~~~~
port_facility.cpp:231:14: warning: ignoring return value of 'int scanf(const char*, ...)', declared with attribute warn_unused_result [-Wunused-result]
         scanf("%d %d", &intervalles[iObjet].debut, &intervalles[iObjet].fin);
         ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...