Cod sursa(job #2340793)

Utilizator SqueekDanielTodasca Daniel SqueekDaniel Data 11 februarie 2019 00:17:31
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.39 kb
#include <bits/stdc++.h>

#define MAXN 100005

int N, Q;
int Parent[MAXN];
std::vector <int> ADC[MAXN];

inline void AddEdge(int X, int Y) {
    ADC[X].push_back(Y);
    ADC[Y].push_back(X);
}

int Ord[MAXN], NChains, C[MAXN], Rang[MAXN],
    LVL[MAXN], V[MAXN];
std::vector <int> Chain[MAXN];

void DFS(int Vertex = 1, int Height = 1) {
    LVL[Vertex] = Height;
    bool bLeaf = true;

    int Heavy = 0;
    Rang[Vertex] = 1;
    for (auto Edge:ADC[Vertex])
        if (!LVL[Edge]) {
            DFS(Edge, Height+1);
            Parent[Edge] = Vertex;

            bLeaf = false;
            if (Rang[Edge] > Rang[Heavy])
                Heavy = Edge;
            Rang[Vertex] += Rang[Edge];
        }

    if (bLeaf)
        C[Vertex] = ++NChains;
    else C[Vertex] = C[Heavy];
    Chain[C[Vertex]].push_back(Vertex);
}

std::vector <int> Tree[MAXN];

#define _Left   2*Index
#define _Right  2*Index+1
#define _Middle (Left+Right)/2

void Init(int treeidx, int Left, int Right, int Index = 1) {
    if (Left == Right) {
        Tree[treeidx][Index] = V[Chain[treeidx][Left]];
        return;
    }

    Init (treeidx, Left, _Middle, _Left);
    Init (treeidx, _Middle+1, Right, _Right);
    Tree[treeidx][Index] = std::max(Tree[treeidx][_Left], Tree[treeidx][_Right]);
}

void BuildTrees() {
    for (int i=1, j; i<=NChains; ++i) {
        std::reverse(Chain[i].begin(), Chain[i].end());
        for (j=0; j<Chain[i].size(); ++j)
            Ord[Chain[i][j]] = j;

        Tree[i].resize(4*Chain[i].size() + 5);
        Init(i, 0, Chain[i].size()-1);
    }
}

std::ifstream In ("heavypath.in");
std::ofstream Out("heavypath.out");

void Update(int treeidx, int Pos, int Left, int Right, int Index = 1) {
    if (Left == Right) {
        Tree[treeidx][Index] = V[Chain[treeidx][Left]];
        return;
    }

    if (Pos <= _Middle) Update(treeidx, Pos, Left, _Middle, _Left);
    else                Update(treeidx, Pos, _Middle+1, Right, _Right);
    Tree[treeidx][Index] = std::max(Tree[treeidx][_Left], Tree[treeidx][_Right]);
}

int Query(int treeidx, int A, int B, int Left, int Right, int Index = 1) {
    if (A <= Left && Right <= B)
        return Tree[treeidx][Index];

    int Max = INT_MIN;
    if (A <= _Middle) Max = Query(treeidx, A, B, Left, _Middle, _Left);
    if (_Middle < B)  Max = std::max(Max, Query(treeidx, A, B, _Middle+1, Right, _Right));
    return Max;
}

int HPDQuery(int X, int Y) {
    int Ans = INT_MIN;
    int A, B;

    while (C[X] != C[Y]) {
        if (LVL[Chain[C[X]][0]] < LVL[Chain[C[Y]][0]])
            std::swap (X, Y);

        A = 0, B = Ord[X];
        Ans = std::max(Ans, Query(C[X], A, B, 0, Chain[C[X]].size()-1));
        X = Parent[Chain[C[X]][0]];
    }   return std::max(Ans, Query(C[X], std::min(Ord[X], Ord[Y]), std::max(Ord[X], Ord[Y]), 0, Chain[C[X]].size()-1));
}

void Citire() {
    In >> N >> Q;
    for (int i=1; i<=N; ++i)
        In >> V[i], Parent[i] = i;
    for (int i=1, X, Y; i<N; ++i)
        In >> X >> Y, AddEdge(X, Y);
}

void Rezolvare() {
    DFS();
    BuildTrees();

    for (int i=1, type, X, Y; i<=Q; ++i) {
        In >> type >> X >> Y;

        if (type) Out << HPDQuery(X, Y) << '\n';
        else
            V[X] = Y,
            Update(C[X], Ord[X], 0, Chain[C[X]].size()-1);
    }
}

int main()
{
    Citire();
    Rezolvare();

    return 0;
}