Cod sursa(job #2923629)

Utilizator Razvan48Capatina Razvan Nicolae Razvan48 Data 16 septembrie 2022 22:02:38
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 9.05 kb
#include <fstream>
#include <vector>

using namespace std;

///Aceasta este solutia unde din radacina pana intr-o frunza oarecare trec prin maxim sqrt(N) lanturi distincte, deoarece aici aleg pe ce nod cobor dupa adancimea maxima din subarborele nodului.
///O sa pun prima solutie ca fiind cea mai eficienta, in O(M * log(N) * log(N)), unde aleg pe ce nod cobor in functie de cat de "greu" e acel nod, adica dupa dimensiunea subarborelui nodului, nu dupa adancimea maxima. Asa voi trece prin maxim log(N) lanturi intre radacina si frunza, mai putin adica.
///Aceasta este solutia putin mai ineficienta, in O(M * sqrt(N) * log(N)). Mai eficienta este in O(M * log(N) * log(N)).

class Parser
{
private:
  static const int BUFF_SIZE = 5000000;

  ifstream in;

  char buffer[BUFF_SIZE];

  int posBuff;

public:
  Parser(char* file)
  {
    in      = ifstream(file);
    posBuff = BUFF_SIZE - 1;

    ios_base::sync_with_stdio(false);
    in.tie(NULL);
  }

  int getInt()
  {
    int rez = 0;

    while (!('0' <= buffer[posBuff] && buffer[posBuff] <= '9'))
    {
      posBuff++;

      if (posBuff == BUFF_SIZE)
      {
        posBuff = 0;
        in.read(buffer, BUFF_SIZE);
      }
    }

    while ('0' <= buffer[posBuff] && buffer[posBuff] <= '9')
    {
      rez = rez * 10 + buffer[posBuff] - '0';
      posBuff++;

      if (posBuff == BUFF_SIZE)
      {
        posBuff = 0;
        in.read(buffer, BUFF_SIZE);
      }
    }

    return rez;
  }
};

Parser input("heavypath.in");

const int NMAX = 100000;
const int LOGMAX = 17;

int v[1 + NMAX];
vector<int> graf[1 + NMAX];

bool vizitatCostJos[1 + NMAX];
int costJos[1 + NMAX];

bool vizitatLanturi[1 + NMAX];
vector<vector<int>> lanturi;

int indexLantNod[1 + NMAX];
int pozLantNod[1 + NMAX];

vector<vector<int>> arboriLanturi;
pair<int, int> tataLant[1 + NMAX];

bool vizitatLCA[1 + NMAX];
vector<int> liniarizareLCA;
int primaAparitieLCA[1 + NMAX];
int adancimeNod[1 + NMAX];
int log2[1 + 2 * NMAX];
pair<int, int> rmq[1 + 2 * NMAX][1 + LOGMAX];

void dfsCostJos(int nod)
{
    vizitatCostJos[nod] = true;
    costJos[nod] = 1;

    for (int i = 0; i < graf[nod].size(); i++)
    {
        int fiu = graf[nod][i];

        if (!vizitatCostJos[fiu])
        {
            dfsCostJos(fiu);
            costJos[nod] = max(costJos[nod], costJos[fiu] + 1);
        }
    }
}

void dfsLCA(int nod)
{
    vizitatLCA[nod] = true;
    liniarizareLCA.push_back(nod);
    primaAparitieLCA[nod] = (int)liniarizareLCA.size() - 1;

    adancimeNod[nod] = 1;

    for (int i = 0; i < graf[nod].size(); i++)
    {
        int fiu = graf[nod][i];

        if (!vizitatLCA[fiu])
        {
            dfsLCA(fiu);
            liniarizareLCA.push_back(nod);

            adancimeNod[nod] = max(adancimeNod[nod], adancimeNod[fiu] + 1);
        }
    }
}

void dfsLanturi(int nod)
{
    vizitatLanturi[nod] = true;
    lanturi.back().push_back(nod);

    int indexLantCurent = (int)lanturi.size() - 1;
    int pozLantCurent = (int)lanturi.back().size() - 1;

    int nodBunJos = -1;
    int costNodBunJos = -1;

    for (int i = 0; i < graf[nod].size(); i++)
    {
        int fiu = graf[nod][i];

        if (!vizitatLanturi[fiu])
        {
            if (costJos[fiu] > costNodBunJos)
            {
                nodBunJos = fiu;
                costNodBunJos = costJos[fiu];
            }
        }
    }

    if (nodBunJos != -1)
        dfsLanturi(nodBunJos);

    for (int i = 0; i < graf[nod].size(); i++)
    {
        int fiu = graf[nod][i];

        if (!vizitatLanturi[fiu] && fiu != nodBunJos)
        {
            lanturi.emplace_back();
            lanturi.back().push_back(0);

            tataLant[(int)lanturi.size() - 1].first = indexLantCurent;
            tataLant[(int)lanturi.size() - 1].second = pozLantCurent;

            dfsLanturi(fiu);
        }
    }
}

void buildAint(int indexLanturi, int index, int st, int dr)
{
    if (st == dr)
    {
        arboriLanturi[indexLanturi][index] = v[lanturi[indexLanturi][st]];
        return;
    }

    int mij = (st + dr) / 2;
    int fiuSt = 2 * index;
    int fiuDr = 2 * index + 1;

    buildAint(indexLanturi, fiuSt, st, mij);
    buildAint(indexLanturi, fiuDr, mij + 1, dr);

    arboriLanturi[indexLanturi][index] = max(arboriLanturi[indexLanturi][fiuSt], arboriLanturi[indexLanturi][fiuDr]);
}

void updateAint(int indexLanturi, int index, int st, int dr, int poz, int val)
{
    if (st == dr)
    {
        arboriLanturi[indexLanturi][index] = val;
        return;
    }

    int mij = (st + dr) / 2;
    int fiuSt = 2 * index;
    int fiuDr = 2 * index + 1;

    if (poz <= mij)
        updateAint(indexLanturi, fiuSt, st, mij, poz, val);
    else
        updateAint(indexLanturi, fiuDr, mij + 1, dr, poz, val);

    arboriLanturi[indexLanturi][index] = max(arboriLanturi[indexLanturi][fiuSt], arboriLanturi[indexLanturi][fiuDr]);
}

int queryAint(int indexLanturi, int index, int st, int dr, int stQ, int drQ)
{
    if (st == stQ && drQ == dr)
    {
        return arboriLanturi[indexLanturi][index];
    }

    int mij = (st + dr) / 2;
    int fiuSt = 2 * index;
    int fiuDr = 2 * index + 1;

    if (drQ <= mij)
        return queryAint(indexLanturi, fiuSt, st, mij, stQ, drQ);
    else if (stQ >= mij + 1)
        return queryAint(indexLanturi, fiuDr, mij + 1, dr, stQ, drQ);
    else
        return max(queryAint(indexLanturi, fiuSt, st, mij, stQ, mij), queryAint(indexLanturi, fiuDr, mij + 1, dr, mij + 1, drQ));
}

void preCalcRMQ()
{
    for (int i = 2; i < liniarizareLCA.size(); i++)
        log2[i] = log2[i / 2] + 1;

    for (int i = 1; i < liniarizareLCA.size(); i++)
    {
        rmq[i][0].first = adancimeNod[liniarizareLCA[i]];
        rmq[i][0].second = liniarizareLCA[i];
    }

    for (int l = 1; (1 << l) < liniarizareLCA.size(); l++)
    {
        for (int i = 1; i + (1 << l) - 1 < liniarizareLCA.size(); i++)
        {
            if (rmq[i][l - 1].first > rmq[i + (1 << (l - 1))][l - 1].first)
            {
                rmq[i][l].first = rmq[i][l - 1].first;
                rmq[i][l].second = rmq[i][l - 1].second;
            }
            else
            {
                rmq[i][l].first = rmq[i + (1 << (l - 1))][l - 1].first;
                rmq[i][l].second = rmq[i + (1 << (l - 1))][l - 1].second;
            }
        }
    }
}

int calcLCA(int x, int y)
{
    if (primaAparitieLCA[x] > primaAparitieLCA[y])
        swap(x, y);

    int st = primaAparitieLCA[x];
    int dr = primaAparitieLCA[y];
    int logaritm2 = log2[dr - st + 1];

    if (rmq[st][logaritm2].first > rmq[dr - (1 << logaritm2) + 1][logaritm2].first)
        return rmq[st][logaritm2].second;
    else
        return rmq[dr - (1 << logaritm2) + 1][logaritm2].second;
}

int calcSol(int jos, int sus)
{
    int sol = -1;

    while (jos != sus)
    {
        if (indexLantNod[jos] == indexLantNod[sus])
        {
            sol = max(sol, queryAint(indexLantNod[jos], 1, 1, (int)lanturi[indexLantNod[jos]].size() - 1, pozLantNod[sus], pozLantNod[jos]));
            jos = sus;
        }
        else
        {
            sol = max(sol, queryAint(indexLantNod[jos], 1, 1, (int)lanturi[indexLantNod[jos]].size() - 1, 1, pozLantNod[jos]));
            jos = lanturi[tataLant[indexLantNod[jos]].first][tataLant[indexLantNod[jos]].second];
        }
    }

    return sol;
}

int main()
{
    ofstream out("heavypath.out");

    int n, m;
    n = input.getInt();
    m = input.getInt();

    for (int i = 1; i <= n; i++)
        v[i] = input.getInt();

    for (int i = 1; i <= n - 1; i++)
    {
        int a, b;
        a = input.getInt();
        b = input.getInt();

        graf[a].push_back(b);
        graf[b].push_back(a);
    }

    dfsCostJos(1);

    lanturi.emplace_back();
    lanturi.emplace_back();
    lanturi.back().push_back(0);

    tataLant[0].first = -1;
    tataLant[0].second = -1;
    tataLant[1].first = -1;
    tataLant[1].second = -1;

    dfsLanturi(1);
    for (int i = 1; i < lanturi.size(); i++)
    {
        for (int j = 1; j < lanturi[i].size(); j++)
        {
            indexLantNod[lanturi[i][j]] = i;
            pozLantNod[lanturi[i][j]] = j;
        }
    }

    arboriLanturi.resize(lanturi.size());
    for (int i = 1; i < lanturi.size(); i++)
        arboriLanturi[i].resize(4 * (int)lanturi[i].size());
    for (int i = 1; i < lanturi.size(); i++)
        buildAint(i, 1, 1, (int)lanturi[i].size() - 1);

    liniarizareLCA.push_back(0);
    dfsLCA(1);
    preCalcRMQ();

    for (int i = 1; i <= m; i++)
    {
        int t, x, y;
        t = input.getInt();
        x = input.getInt();
        y = input.getInt();

        if (t == 0)
            updateAint(indexLantNod[x], 1, 1, (int)lanturi[indexLantNod[x]].size() - 1, pozLantNod[x], y);
        else
        {
            int stramos = calcLCA(x, y);

            out << max(calcSol(x, stramos), calcSol(y, stramos)) << '\n';
        }
    }

    return 0;
}