제출 #1162829

#제출 시각아이디문제언어결과실행 시간메모리
1162829Noname_1900Mergers (JOI19_mergers)C++20
10 / 100
102 ms44928 KiB
#include<bits/stdc++.h>
using namespace std;
const int NMAX = 500000+1;
const int INFINI = 1e9;
int boss[NMAX];
vector<int> chemins[NMAX];
int prem[NMAX];
int nbComposantesTotal;
int findBoss(int noeud)
{
    if(boss[noeud] == noeud)    return noeud;
    return boss[noeud] = findBoss(boss[noeud]);
}
int sizeComp[NMAX];
void merge(int a, int b)
{
    a = findBoss(a);
    b = findBoss(b);
    if(a == b)  return;
    if(sizeComp[b]>sizeComp[a])
    {
        swap(a, b);
    }
    sizeComp[a] += sizeComp[b];
    boss[b] = a;
    nbComposantesTotal--;
}
bool vuCompo[NMAX];
vector<int> parcoursVu;
int numero[NMAX];

int nbSuiteMaint;
/*
void parcourir(int noeud, int anc)
{
    nbSuiteMaint++;
    numero[noeud] = nbSuiteMaint;
    int bossNoeud = findBoss(noeud);
    if(vuCompo[bossNoeud])
    {
        while((findBoss(*parcoursVu.rbegin()) != findBoss(bossNoeud))&&(!parcoursVu.empty()))
        {
            merge(bossNoeud, *parcoursVu.rbegin());
            parcoursVu.pop_back();
        }
    }
    else
        vuCompo[bossNoeud] = true;
    parcoursVu.push_back(noeud);

    for(int pro : chemins[noeud])
    {
        if(pro == anc)  continue;
        int res = 0;
        parcourir(pro, noeud);       //Avoir
        parcoursVu.push_back(noeud);
    }
    //AAdapter
}
    /** */
vector<int> parcoursLCA;
int placeDansParc[NMAX];
int parcoursVersNoeud[NMAX];
int pere[NMAX];
void parcourir(int noeud, int anc)
{
    pere[noeud] = anc;
    nbSuiteMaint++;
    numero[noeud] = nbSuiteMaint;
    parcoursVersNoeud[nbSuiteMaint] = noeud;
    placeDansParc[noeud] = parcoursLCA.size();
    parcoursLCA.push_back(numero[noeud]);
    for(int pro : chemins[noeud])
    {
        if(pro == anc)  continue;
        parcourir(pro, noeud);
        parcoursLCA.push_back(numero[noeud]);
    }
}
int arbre[NMAX*2+1];
pair<int, int> debFin[NMAX*2+1];

int base(int noeud, int deb, int fin)
{
    debFin[noeud] = {deb, fin};
    if(deb == fin-1)    return arbre[noeud] = parcoursLCA[deb];
    int milieu = (deb+fin)/2;
    return arbre[noeud] = min(base(noeud*2, deb, milieu), base(noeud*2+1, milieu, fin));
}
int trouverMin(int noeud, int deb, int fin)
{
    if((debFin[noeud].first >= fin) || (debFin[noeud].second <= deb))   return INFINI;
    if((debFin[noeud].first >= deb) && (debFin[noeud].second <= fin))   return arbre[noeud];
    return min(trouverMin(noeud*2, deb, fin), trouverMin(noeud*2+1, deb, fin));
}
vector<int> clubs[NMAX];
int dejaVU[NMAX];
bool assure[NMAX];
void parcoursFin(int noeud, int anc)
{
   // cout << noeud << " mkm " << endl;
    for(int pro : chemins[noeud])
    {
       // cout << noeud << " " << pro << endl;
        if(pro == anc)  continue;
       // cout << noeud << " " << pro << endl;
        //*
        if(findBoss(pro) != findBoss(noeud))
        {
            if(!assure[findBoss(noeud)])    nbComposantesTotal --;
            assure[findBoss(noeud)] = true;
        }
            /** */
        parcoursFin(pro, noeud);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int N, K;
    cin >> N >> K;
    nbComposantesTotal = K;
    nbSuiteMaint = 0;
    for(int i = 1; i <= N-1; i++)
    {
        int a, b;
        cin >> a>>b;
        chemins[a].push_back(b);
        chemins[b].push_back(a);
    }
    for(int i = 1; i <= N; i++)
    {
        int famille;
        cin >> famille;
        if(prem[famille] == 0)
        {
            prem[famille] = i;
        }
        clubs[famille].push_back(i);
        boss[i] = prem[famille];
        sizeComp[i] = 1;
    }
    parcourir(1, 0);
    base(1, 0, parcoursLCA.size());
   // for(int i : parcoursLCA)    cout << parcoursVersNoeud[i] << " ";
   // cout << endl;
    
    for(int iFamille = 1; iFamille <= K; iFamille++)
    {
      //  cout << "deb " << iFamille << endl;
        int minElem = INFINI, maxElem = 0;
        for(int iElem : clubs[iFamille])
        {
            int posElem = placeDansParc[iElem];
            minElem = min(minElem, posElem);
            maxElem = max(maxElem, posElem);
        }
        int lca = trouverMin(1, minElem, maxElem+1);
        int noeudLCA = parcoursVersNoeud[lca];
        for(int iElem : clubs[iFamille])
        {
            while(iElem != noeudLCA)
            {
                if(dejaVU[iElem] == iFamille)   break;
                dejaVU[iElem] = iFamille;
                merge(iElem, prem[iFamille]);
                iElem = pere[iElem];
            }
        }
        merge(noeudLCA, prem[iFamille]);
    }
    if(nbComposantesTotal == 1)
    {
        cout << 0;
        return 0;
    }
    /*
    for(int i = 1; i <= N; i++)
    {
        cout << findBoss(i) << " ";
    }
    cout << endl;
    cout << nbComposantesTotal << endl;
    /** */
    int origine = 1;
    while((origine <= N) && (chemins[origine].size() == 1)) origine++;
    parcoursFin(origine, 0);
   // cout << nbComposantesTotal<< "\n";
    double rep = nbComposantesTotal;
    double autre = 2;
   // for(int i = 1; i <= N; i++) cout << assure[i] << " ";
    //cout << endl;
    cout << ceil(rep/autre);
}
#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...