Cod sursa(job #2191415)

Utilizator felixiPuscasu Felix felixi Data 2 aprilie 2018 19:24:34
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.82 kb
#include <bits/stdc++.h>

using namespace std;

const int NMAX = 1e5 + 2;
const int INF  = (1 << 30);

int val[NMAX+2];

struct Atom
{
    int cnt, val;

    Atom(int cnt = 0, int val = -INF) : cnt(cnt), val(val) {}

    Atom operator + (const Atom& o) const
    {
        return Atom(cnt + o.cnt, max(val, o.val));
    }
};

struct SegmentTree
{
    vector<Atom> aint;
    int N;

    SegmentTree(int n = 1) : aint(vector<Atom>(4*n + 1, Atom())), N(n) {}

    void update(int nod, int st, int dr, int pos, int val)
    {
        if( pos < st || dr < pos ) return ;
        if( st == dr ) {
            aint[nod] = Atom(1, val);
            return ;
        }

        int m = (st + dr) / 2;
        update(2*nod, st, m, pos, val);
        update(2*nod + 1, m + 1, dr, pos, val);

        aint[nod] = (aint[2*nod] + aint[2*nod + 1]);
    }

    void update(int pos, int val)
    {
        assert( 1 <= pos && pos <= N );

        update(1, 1,N, pos, val);
    }

    int query(int nod, int st, int dr, int x, int y)
    {
        if( y < st || dr < x ) return -INF;

        if( x <= st && dr <= y ) return aint[nod].val;

        int m = (st + dr) / 2;
        return max( query(2*nod, st, m, x, y), query(2*nod + 1, m + 1, dr, x, y) );
    }

    int query(int x, int y)
    {
        return query(1, 1,N, x, y);
    }
};

namespace HLD
{
    const int SZ = 1e5 + 2;

    /// one time use only, reset by hand if necessary
    int N;
    int root[SZ];
    int parent[SZ], where[SZ], weight[SZ], depth[SZ];
    int nr_lant = 0, lg[SZ];

    vector<vector<int>> nodes;
    vector<SegmentTree> aint;

    void dfs(vector<int>(& G)[SZ], int nod, int tata = -1)
    {
        weight[nod] = 1;

        int greu = 0;
        for( int x : G[nod] ) {
            if( x == tata ) continue;
            parent[x] = nod;
            depth[x] = depth[nod] + 1;

            dfs(G, x, nod);
            weight[nod] += weight[x];

            if( !greu || weight[greu] < weight[x] )
                greu = x;
        }
        if( greu == 0 ) {
            where[nod] = nr_lant;
            lg[ where[nod] ] = 1;
            root[nod] = nod;
            aint.push_back(SegmentTree());
            ++nr_lant;
        }
        else {
            where[nod] = where[greu];
            lg[ where[nod] ] ++;
            root[nod] = root[greu];
        }
        for( int x : G[nod] ) {
            if( x == tata ) continue;
            if( x != greu )
                aint[ where[x] ] = SegmentTree( lg[ where[x] ] );
        }
        if( tata == -1 )
            aint[ where[nod] ] = SegmentTree( lg[ where[nod] ] );
    }

    void recalc_root()
    {
        for( int i = 1;  i <= N;  ++i ) {
            if( root[i] == i ) {
                int old_root = i;
                int new_root = old_root;
                while( root[ parent[new_root] ] == old_root )
                    new_root = parent[new_root];
                for( int x = old_root;  root[x] == old_root;   x = parent[x] )
                    root[x] = new_root;
            }
        }
    }

    void make_hld(vector<int>(& G)[SZ], int input_size)
    {
        N = input_size;

        depth[1] = 1;
        parent[1] = 0;
        weight[0] = 0;
        dfs(G, 1);
        recalc_root();
    }

    inline int treePos(int nod)
    {
        return depth[nod] - depth[ root[nod] ] + 1;
    }

    void update(int nod, int val)
    {
        int pos = treePos(nod);
        assert(pos <= aint[ where[nod] ].N);

        aint[ where[nod] ].update(pos, val);
    }

    int query(int x, int y)
    {
        assert( 1 <= root[x] && root[x] <= N );
        assert( 1 <= root[y] && root[y] <= N );

        int ret = -INF;
        while( root[x] != root[y] ) {
            if( depth[ root[x] ] < depth[ root[y] ] ) swap(x, y);
            ret = max( ret, aint[ where[x] ].query( 1, treePos(x) ) );
            x = parent[ root[x] ];
        }
        if( depth[x] > depth[y] ) swap(x, y);
        ret = max( ret, aint[ where[x] ].query( treePos(x), treePos(y) ) );

        assert( 0 <= ret && ret <= 2000000000 );

        return ret;
    }
}

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

vector<int> G[NMAX];
int N, Q;

int main()
{
    in >> N >> Q;
    for( int i = 1;  i <= N;  ++i ) in >> val[i];
    for( int i = 1;  i < N;  ++i ) {
        int x,y;
        in >> x >> y;
        G[x].push_back(y);
        G[y].push_back(x);
    }
    HLD::make_hld(G, N);
    for( int i = 1;  i <= N;  ++i )
        HLD::update(i, val[i]);

    for( int i = 1;  i <= Q;  ++i ) {
        int t,x,y;
        in >> t >> x >> y;
        if( t == 0 ) {
            HLD::update(x, y);
        }
        else
            out << HLD::query(x, y) << '\n';
    }
    return 0;
}