Cod sursa(job #1820679)

Utilizator CiurezAndreiCiurez Marius-Andrei CiurezAndrei Data 2 decembrie 2016 00:55:53
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.88 kb
#include <bits/stdc++.h>

#define DIM 100010

using namespace std;

ifstream fin("heavypath.in");
ofstream fout("heavypath.out");

int N, M, numberLanturi;
int v[DIM], niv[DIM], w[DIM], lant[DIM];
int AINT[4 * DIM];
int lantTata[DIM], lantNiv[DIM], lantPoz[DIM], lantDim[DIM];
vector<int> L[DIM], Path[DIM];
bitset<DIM> viz;


inline void DFS(const int &node)
{
    viz[node] = 1;
    w[node] = 1; // "greutatea" subarborelui node
    int weightNode = -1; // vecinul cel mai "greu"
    bool leaf = true;

    for(int i = 0; i < L[node].size(); i ++)
    {
        if(viz[ L[node][i] ] == 0)
        {
            leaf = false;
            niv[ L[node][i] ] = niv[node] + 1;
            DFS(L[node][i]);
            w[node] += w[ L[node][i] ]; //cresc greutatea
            if(weightNode == -1)
            {
                weightNode = L[node][i];
            }
            else
            {
                if(w[weightNode] < w[ L[node][i] ])
                {
                    weightNode = L[node][i]; // actualizez cel mai "greu" vecin
                }
            }
        }
    }

    if(leaf == true)
    {
        lant[node] = ++numberLanturi; // lantul incepe din frunza
        lantDim[numberLanturi] = 1; // dimensiunea lantului
        Path[numberLanturi].push_back(node); //drumul
        return;
    }

    lant[node] = lant[weightNode];
    ++lantDim[ lant[node] ];
    Path[ lant[node] ].push_back(node);

    for(int i = 0; i < L[node].size(); i ++)
    {
        if(L[node][i] == weightNode || niv[ L[node][i] ] < niv[node])
        {
            continue;
        }
        lantTata[ lant[ L[node][i] ] ] = node; // tatal lantului lui L[node][i] este lantul lui node
        lantNiv [ lant[ L[node][i] ] ] = niv[node]; // nivelul lantului lui L[node][i] este nivelul lui node

    }

}

inline void build(const int& node, const int& left, const int &right, const int &decalaj, const int &nrLant)
{
    if(left == right)
    {
        AINT[node + decalaj] = v[ Path[nrLant][left - 1] ]; // in frunza am valoarea nodului din lantul nrLant;
        return;
    }

    int middle = (left + right) >> 1;

    build(2 * node, left, middle, decalaj, nrLant);
    build(2 * node + 1, middle + 1, right, decalaj, nrLant);

    AINT[node + decalaj] = max( AINT[2 * node + decalaj], AINT[2 * node + 1 + decalaj] );
}

inline void update(const int& node, const int& left, const int &right, const int &poz, const int &val,  const int &decalaj)
{
    if(left == right)
    {
        AINT[node + decalaj] = val;
        return;
    }

    int middle = (left + right) >> 1;

    if(poz <= middle)
    {
        update(2 * node, left, middle, poz, val,  decalaj);
    }
    else
    {
        update(2 * node + 1, middle + 1, right, poz, val, decalaj);
    }

    AINT[node + decalaj] = max( AINT[2 * node + decalaj], AINT[2 * node + 1 + decalaj] );
}

inline int query(const int &node, const int &left, const int &right, const int &posx, const int &posy, const int &decalaj)
{
    if(posx <= left && right <= posy)
    {
        return AINT[node + decalaj];
    }

    int middle = (left + right) >> 1, solution = 0;

    if(posx <= middle)
    {
        solution = max(solution, query(2 * node, left, middle, posx, posy, decalaj) );
    }
    if(middle < posy)
    {
        solution = max(solution, query(2 * node + 1, middle + 1, right, posx, posy, decalaj) );
    }

    return solution;
}


int main()
{
    fin >> N >> M;
    for(int i = 1; i <= N; i ++)
    {
        fin >> v[i];
    }
    for(int i = 1; i < N; i ++)
    {
        int a, b;
        fin >> a >> b;
        L[a].push_back(b);
        L[b].push_back(a);
    }

    niv[1] = 1;
    DFS(1);
    for(int i = 1; i <= numberLanturi; i ++)
    {
        reverse(Path[i].begin(), Path[i].end()); // il sortam crescator dupa nivel, era sortat descrescator datorita actualizarii pe revenirea DFS-ului

        if(i > 1)
        {
            lantPoz[i] = lantPoz[i - 1] + lantDim[i - 1] * 4; // la AINT am nevoie de 4 * dimensiune, asa ca voi decala lanturile la dreapta cu 4 * dimensiunea celui anterior
        }
        build(1, 1, lantDim[i], lantPoz[i], i); // build la left 1, right lantDim[i], lantul este decalat cu lantPoz[i], i-lea lant
    }

    for(int i = 1; i <= M; i ++)
    {
        int type, x , y;
        fin >> type >> x >> y;
        if(type == 0)
        {
            update(1, 1, lantDim[ lant[x] ], niv[x] - lantNiv[ lant[x] ], y, lantPoz[ lant[x] ]);
            /// update la left 1, right dimensiunea lantului lui x, pozitia lui x in lant este niv[x] - lantNiv[ lant[x] ], valoare y, decalaj lantPoz[ lant[x] ]
        }
        else
        {
            int solution = 0;

            while(1)
            {
                if(lant[x] == lant[y]) // x si y sunt in acelasi lant - cazul "fericit"
                {
                    if(niv[x] > niv[y])
                    {
                        swap(x, y);
                    }
                    solution = max(solution, query(1, 1, lantDim[ lant[x] ], niv[x] - lantNiv[ lant[x] ], niv[y] - lantNiv[ lant[x] ], lantPoz[ lant[x] ]) );
                    /// query la 1, left 1 right lungimea lantului lui x si y, pozitia lui x, pozitia lui y, decalajul lantului lui x si y
                    break;
                }

                if(lantNiv[ lant[x] ] < lantNiv[ lant[y] ])
                {
                    swap(x, y);
                }

                solution = max(solution, query(1, 1, lantDim[ lant[x] ], 1, niv[x] - lantNiv[ lant[x] ], lantPoz[ lant[x] ]));
                /// query la 1, left 1, right dimensiunea lantului lui x, inceputul lantului, pozitia lui x in lant, decalaj;
                x = lantTata[ lant[x] ]; // x = tatal lantului lui x;
            }
            fout << solution << '\n';
        }

    }
    return 0;
}