Cod sursa(job #1098324)

Utilizator AlexandruValeanuAlexandru Valeanu AlexandruValeanu Data 4 februarie 2014 18:55:45
Problema Heavy Path Decomposition Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 6.47 kb
#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

const int Nmax = 100001;

class Scanner
{
    private:

        const int BUF_SIZE = 1 << 21;
        char *buffer;
        int position = BUF_SIZE;

        inline char getChar()
        {
            if ( position == BUF_SIZE )
            {
                fread( buffer, 1, BUF_SIZE, stdin );
                position = 0;
            }

            return buffer[ position++ ];
        }

    public:

        Scanner()
        {
            buffer = new char[BUF_SIZE];
        }

        int nextInt()
        {
            int nr = 0;
            char c;

            do
            {
                c = getChar();

            } while ( !isdigit( c ) );

            do
            {
                nr = nr * 10 + c - '0';
                c = getChar();

            } while ( isdigit( c ) );

            return nr;
        }
};

class SegmentTree
{
    public:

        SegmentTree( const int n, const vector<int> values )
        {
            if ( n == 0 ) return;

            int sz = 4 * n;
            N = n;

            Tree = new int[sz];

            build( 1, 0, N - 1, values );
        }

        void update( const int position, const int value )
        {
           update( 1, 0, N - 1, position, value );
        }

        int query( const int st, const int dr )
        {
            return query( 1, 0, N - 1, st, dr );
        }

    private:

        int N;
        int *Tree;

        int middle( int i, int j )
        {
            return i + ( j - i ) / 2;
        }

        inline int Lson( const int nod )
        {
            return nod * 2;
        }

        inline int Rson( const int nod )
        {
            return nod * 2 + 1;
        }

        inline void update_tree( const int nod )
        {
            Tree[nod] = max( Tree[ Lson( nod ) ], Tree[ Rson( nod ) ] );
        }

        void build( int nod, int st, int dr, const vector<int> values )
        {
            if ( st == dr )
            {
                Tree[nod] = values[st];
            }
            else
            {
                int m = middle( st, dr );

                build( Lson( nod ), st, m, values );
                build( Rson( nod ), m + 1, dr, values );

                update_tree( nod );
            }
        }

        void update( int nod, int st, int dr, const int position, const int value )
        {
            if ( st == dr )
            {
                Tree[nod] = value;
            }
            else
            {
                int m = middle( st, dr );

                if ( position <= m )
                        update( Lson( nod ), st, m, position, value );
                else
                        update( Rson( nod ), m + 1, dr, position, value );

                update_tree( nod );
            }
        }

        int query( int nod, int st, int dr, int st_query, int dr_query )
        {
            if ( st_query <= st && dr <= dr_query )
            {
                return Tree[nod];
            }
            else
            {
                int value = -1;
                int m = middle( st, dr );

                if ( st_query <= m )
                        value = max( value, query( Lson( nod ), st, m, st_query, dr_query ) );

                if ( m < dr_query )
                        value = max( value, query( Rson( nod ), m + 1, dr, st_query, dr_query ) );

                return value;
            }
        }

};

vector <int> Graph[Nmax];
int value[Nmax];
int size[Nmax], father[Nmax], level[Nmax], path[Nmax], length_path[Nmax];
int pos_in_path[Nmax], start_node[Nmax];

vector <SegmentTree> SegmentTrees;
int Number_Of_Paths;

int N, Q;

void DFS( int nod )
{
    int heaviestSon = 0;
    size[nod] = 1;

    for ( auto son: Graph[nod] )
            if ( father[son] == 0 )
            {
                father[son] = nod;
                level[son] = level[nod] + 1;
                DFS( son );

                size[nod] += size[son];

                if ( size[heaviestSon] < size[son] )
                        heaviestSon = son;
            }

    if ( heaviestSon == 0 )
            path[nod] = Number_Of_Paths++;
    else
            path[nod] = path[heaviestSon];

    pos_in_path[nod] = length_path[ path[nod] ]++;
}

void build_heavy_path_decomposition()
{
    father[1] = 1;
    level[1] = 0;
    DFS( 1 );

    for ( int i = 1; i <= N; ++i )
    {
        pos_in_path[i] = length_path[ path[i] ] - pos_in_path[i] - 1;

        if ( pos_in_path[i] == 0 )
                start_node[ path[i] ] = i;
    }
}

void build_segment_trees()
{
    vector < vector<int> > pathValue = vector < vector<int> >( Number_Of_Paths );

    for ( int i = 0; i < Number_Of_Paths; ++i )
            pathValue[i] = vector<int>( length_path[i] );

    for ( int i = 1; i <= N; ++i )
            pathValue[ path[i] ][ pos_in_path[i] ] = value[i];

    for ( int i = 0; i < Number_Of_Paths; ++i )
            SegmentTrees.push_back( SegmentTree( pathValue[i].size(), pathValue[i] ) );
}

int query( int x, int y )
{
    if ( level[ start_node[ path[x] ] ] < level[ start_node[ path[y] ] ] )
            swap( x, y );

    if ( path[x] == path[y] )
            return SegmentTrees[ path[x] ].query( min( pos_in_path[x], pos_in_path[y] ), max( pos_in_path[x], pos_in_path[y] ) );
    else
            return max( SegmentTrees[ path[x] ].query( 0, pos_in_path[x] ), query( father[ start_node[ path[x] ] ], y ) );
}

int main()
{
    freopen("heavypath.in", "r", stdin);
    freopen("heavypath.out", "w", stdout);

    Scanner scan;

    N = scan.nextInt();
    Q = scan.nextInt();

    for ( int i = 1; i <= N; ++i )
            value[i] = scan.nextInt();

    for ( int i = 1, a, b; i < N; ++i )
    {
        a = scan.nextInt();
        b = scan.nextInt();

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

    build_heavy_path_decomposition();
    build_segment_trees();

    for ( int i = 1, tip, a, b; i <= Q; ++i )
    {
        tip = scan.nextInt();
        a = scan.nextInt();
        b = scan.nextInt();

        if ( tip == 0 )
        {
            value[a] = b;
            SegmentTrees[ path[a] ].update( pos_in_path[a], b );
        }
        else
        {
            printf("%d\n", query( a, b ));
        }
    }

    return 0;
}