Cod sursa(job #2225990)

Utilizator HumikoPostu Alexandru Humiko Data 29 iulie 2018 01:37:02
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.55 kb
#include <bits/stdc++.h>

using namespace std;

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

int n, m, no_of_Streaks;

int v[100005];
int level[100005];
int father[100005];
int sons[100005];
int location_of_Node[100005];
int position_in_Heavy_Path[100005];

vector <int> graph[100005];
vector <int> interval_Tree[100005];
vector <int> heavy_Path[100005];

void buildIntervalTrees(int node, int left, int right, int current_Tree)
{
    if ( left == right )
    {
        interval_Tree[current_Tree][node] = v[heavy_Path[current_Tree][left]];
        return;
    }

    int middle = left+(right-left)/2;

    buildIntervalTrees(2*node, left, middle, current_Tree);
    buildIntervalTrees(2*node+1, middle+1, right, current_Tree);

    interval_Tree[current_Tree][node] = max(interval_Tree[current_Tree][2*node], interval_Tree[current_Tree][2*node+1]);
}

void updateIntervalTree(int node, int left, int right, int position, int value, int current_Tree)
{
    if ( left == right )
    {
        interval_Tree[current_Tree][node] = value;
        return;
    }

    int middle = left+(right-left)/2;

    if ( position <= middle )
        updateIntervalTree(2*node, left, middle, position, value, current_Tree);
    else
        updateIntervalTree(2*node+1, middle+1, right, position, value, current_Tree);

    interval_Tree[current_Tree][node] = max(interval_Tree[current_Tree][2*node], interval_Tree[current_Tree][2*node+1]);
}

int query(int node, int left, int right, int a, int b, int current_Tree)
{
    if ( left >= a && right <= b )
        return interval_Tree[current_Tree][node];

    int answer_on_Left = 0, answer_on_Right = 0;
    int middle = left+(right-left)/2;

    if ( a <= middle )
        answer_on_Left = query(2*node, left, middle, a, b, current_Tree);
    if ( b > middle )
        answer_on_Right = query(2*node+1, middle+1, right, a, b, current_Tree);

    return max(answer_on_Left, answer_on_Right);
}

int findTheMaximumValue(int first_Node, int second_Node)
{
    int a, b, answer = 0;
    int location_of_First_Node = location_of_Node[first_Node];
    int location_of_Second_Node = location_of_Node[second_Node];

    if ( location_of_First_Node == location_of_Second_Node )
    {
        a = min(position_in_Heavy_Path[first_Node], position_in_Heavy_Path[second_Node]);
        b = max(position_in_Heavy_Path[first_Node], position_in_Heavy_Path[second_Node]);

        answer = max(answer, query(1, 1, (int)heavy_Path[location_of_First_Node].size()-1, a, b, location_of_First_Node));
    }
    else
    {
        int last_of_First_Heavy_Path = (int)heavy_Path[location_of_First_Node].size()-1;
        int last_of_Second_Heavy_Path = (int)heavy_Path[location_of_Second_Node].size()-1;

        if ( level[heavy_Path[location_of_First_Node][last_of_First_Heavy_Path]] < level[heavy_Path[location_of_Second_Node][last_of_Second_Heavy_Path]] )
        {
            swap (first_Node, second_Node);
            swap (location_of_First_Node, location_of_Second_Node);
            swap (last_of_First_Heavy_Path, last_of_Second_Heavy_Path);
        }

        a = position_in_Heavy_Path[first_Node];
        b = (int)heavy_Path[location_of_First_Node].size()-1;

        int maximum_in_First_Path = query(1, 1, (int)heavy_Path[location_of_First_Node].size()-1, a, b, location_of_First_Node);
        int maximum_in_Second_Path = findTheMaximumValue(father[heavy_Path[location_of_First_Node][last_of_First_Heavy_Path]], second_Node);
        answer = max(maximum_in_First_Path, maximum_in_Second_Path);
    }
    return answer;
}

void buildHeavyPath(int node, int parent)
{
    father[node] = parent;
    level[node] = level[parent]+1;
    sons[node] = 1;

    for ( auto x:graph[node] )
    {
        if ( x == parent)
            continue;

        buildHeavyPath(x, node);
        sons[node] += sons[x];
    }

    if ( sons[node] == 1 )
    {
        no_of_Streaks++;
        position_in_Heavy_Path[node] = 1;
        location_of_Node[node] = no_of_Streaks;
        heavy_Path[no_of_Streaks].push_back(0);
        heavy_Path[no_of_Streaks].push_back(node);
        return;
    }

    int best_Path = 0;

    for ( auto x:graph[node] )
    {
        if ( x == parent )
            continue;

        if ( sons[x] > sons[best_Path] )
            best_Path = x;
    }

    location_of_Node[node] = location_of_Node[best_Path];
    heavy_Path[location_of_Node[best_Path]].push_back(node);
    position_in_Heavy_Path[node] = (int)heavy_Path[location_of_Node[best_Path]].size()-1;
}

void readAndSolveQueries()
{
    for ( int i = 1; i <= m; ++i )
    {
        int t, x, y;
        fin>>t>>x>>y;

        if ( t == 0 )
            updateIntervalTree(1, 1, (int)heavy_Path[location_of_Node[x]].size()-1, position_in_Heavy_Path[x], y, location_of_Node[x]);
        else
            fout<<findTheMaximumValue(x, y)<<'\n';
    }
}

void readTree()
{
    fin>>n>>m;
    for ( int i = 1; i <= n; ++i )
        fin>>v[i];

    for ( int i = 1; i < n; ++i )
    {
        int first_Node, second_Node;
        fin>>first_Node>>second_Node;

        graph[first_Node].push_back(second_Node);
        graph[second_Node].push_back(first_Node);
    }
}


int main()
{
    readTree();
    buildHeavyPath(1, 0);

    for ( int i = 1; i <= no_of_Streaks; ++i )
    {
        int size_of_Tree = (int)heavy_Path[i].size()*4;
        interval_Tree[i].resize(size_of_Tree);
        buildIntervalTrees(1, 1, heavy_Path[i].size()-1, i);
    }

    readAndSolveQueries();
}