Cod sursa(job #932464)

Utilizator tzipleatudTudor Tiplea tzipleatud Data 28 martie 2013 22:23:36
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.03 kb
#include <fstream>
#include <vector>
#include <algorithm>
#define NM 100010

using namespace std;

ifstream f("heavypath.in");
ofstream g("heavypath.out");

int N, M;
int NoChains;
int ANS;
int DFLevel[NM], Weight[NM], Value[NM];
bool Visited[NM];
int Chain[NM], ChainFather[NM], ChainLevel[NM], ChainDimension[NM];
int ChainPosition[NM], ChainBegin[NM];
int AI[8*NM];
vector<int> ChainVertex[NM];
vector<int> G[NM];

int DF (int Node, int Father)
{
    Visited[Node]=1;
    Weight[Node]=1;

    bool Leaf=1;
    int Heaviest=0;

    for (vector<int>::iterator it=G[Node].begin(); it!=G[Node].end(); ++it)
        if (Visited[*it]==0)
        {
            Leaf=0;
            DFLevel[*it]=DFLevel[Node]+1;
            DF(*it, Node);
            Weight[Node]+=Weight[*it];

            if (Weight[*it]>Weight[Heaviest] || Heaviest==0)
                Heaviest=*it;  // determin fiul cu cele mai multe noduri in subarbore
        }

    if (Leaf==1) // nodul curent e frunza, care determina un nou lant
    {
        Chain[Node]=++NoChains;
        ChainDimension[NoChains]++;
        ChainVertex[NoChains].push_back(Node);
    }
    else // il adaug lantului de care apartine nodul Heaviest
    {
        Chain[Node]=Chain[Heaviest];
        ChainDimension[Chain[Heaviest]]++;
        ChainVertex[Chain[Heaviest]].push_back(Node);

        for (vector<int>::iterator it=G[Node].begin(); it!=G[Node].end(); ++it)
            if (*it!=Father && *it!=Heaviest)
            {
                ChainFather[Chain[*it]]=Node; // setez pentru fiecare lant din subarborele nodului, care este tatal si nivelul acestui lant
                ChainLevel[Chain[*it]]=DFLevel[Node];
            }
    }
}

void Build (int Node, int S, int D, int Delay, int WChain)
{
    if (S>=D)
    {
        AI[Node+Delay]=Value[ChainVertex[WChain][S-1]];
        return;
    }

    int M=(S+D)/2;

    Build(2*Node, S, M, Delay, WChain);
    Build(2*Node+1, M+1, D, Delay, WChain);

    AI[Node+Delay]=max(AI[2*Node+Delay], AI[2*Node+1+Delay]);
}

void PathDecomposition ()
{
    DFLevel[1]=1;
    DF(1, 0);

    int i, j;
    vector<int>::iterator it;
    for (i=1; i<=NoChains; i++)
    {
        reverse(ChainVertex[i].begin(), ChainVertex[i].end()); // ca sa am nodurile in ordine crescatoare a adancimii

        for (it=ChainVertex[i].begin(), j=1; it!=ChainVertex[i].end(); ++it, ++j)
            ChainPosition[*it]=j;

        ChainBegin[i]=ChainBegin[i-1]+4*ChainDimension[i-1]; // calculez decalaju in AINT
        Build(1, 1, ChainDimension[i], ChainBegin[i], i);
    }
}

void Update (int Node, int S, int D, int Delay, int Pos, int NewVal)
{
    if (S>=D)
    {
        AI[Node+Delay]=NewVal;
        return;
    }

    int M=(S+D)/2;

    if (Pos<=M)
        Update(2*Node, S, M, Delay, Pos, NewVal);
    else
        Update(2*Node+1, M+1, D, Delay, Pos, NewVal);

    AI[Node+Delay]=max(AI[2*Node+Delay], AI[2*Node+1+Delay]);
}

void Query (int Node, int S, int D, int Delay, int L, int R)
{
    if (L<=S && D<=R)
    {
        ANS=max(ANS, AI[Node+Delay]);
        return;
    }

    int M=(S+D)/2;

    if (L<=M)
        Query(2*Node, S,  M, Delay, L, R);
    if (R>M)
        Query(2*Node+1, M+1, D, Delay, L, R);
}

int main ()
{
    f >> N >> M;

    for (int i=1; i<=N; i++)
        f >> Value[i];

    for (int i=1; i<N; i++)
    {
        int a, b;
        f >> a >> b;
        G[a].push_back(b);
        G[b].push_back(a);
    }

    PathDecomposition();

    for (int i=1; i<=M; i++)
    {
        int t;
        f >> t;

        if (t==0)
        {
            int node, value;
            f >> node >> value;
            // updatez in arborele de intervale corespunzator nodului, noua sa valoare
            Update(1, 1, ChainDimension[Chain[node]], ChainBegin[Chain[node]], ChainPosition[node], value);
        }
        else
        {
            int a, b;
            f >> a >> b;
            ANS=0;

            while (1)
            {
                if (Chain[a]==Chain[b])
                {
                    if (DFLevel[a]>DFLevel[b])
                        swap(a, b);

                    // a si b sunt din acelasi lant, deci pot cauta raspunsul in aint-ul corespunzator acelui lant
                    Query(1, 1, ChainDimension[Chain[a]], ChainBegin[Chain[a]], ChainPosition[a], ChainPosition[b]);
                    break;
                }

                if (ChainLevel[Chain[a]]<ChainLevel[Chain[b]])
                    swap(a, b);
                // a si b sunt din lanturi diferite, il iau pe a cel mai de jos
                // il duc in "varful" lantului (adica fac query pe aint-ul corespunzator lantului, intre "varf" si a
                Query(1, 1, ChainDimension[Chain[a]], ChainBegin[Chain[a]], 1, ChainPosition[a]);
                // apoi ma duc in tatale lantului curent
                a=ChainFather[Chain[a]];
            }

            g << ANS << '\n';
        }
    }

    f.close();
    g.close();

    return 0;
}