Cod sursa(job #1866154)

Utilizator eukristianCristian L. eukristian Data 2 februarie 2017 18:15:13
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.61 kb
#include <cstdio>
#include <vector>
#include <algorithm>
#define MAXN 100001
int N, M;
bool visited[MAXN];
int v[MAXN], parent[MAXN], level[MAXN], subtree_size[MAXN];
int path[MAXN], path_parent[MAXN], last_path;
int segtree[4*MAXN], st_offsets[MAXN];
std::vector<int> neigh[MAXN], paths[MAXN];

void dfs(int nod)
{
    int heaviest_child = -1;
    visited[nod] = 1;
    subtree_size[nod] = 1;

    for (auto it = neigh[nod].begin(); it != neigh[nod].end(); ++it)
    {
        if (visited[*it])
        {
            continue;
        }

        level[*it] = level[nod] + 1;
        visited[*it] = 1;
        dfs(*it);
        subtree_size[nod] += subtree_size[*it];

        if (-1 == heaviest_child || subtree_size[*it] > subtree_size[heaviest_child])
        {
            heaviest_child = *it;
        }
    }

    if (-1 == heaviest_child)
    {
        path[nod] = ++last_path;
        paths[last_path].push_back(nod);
    }
    else
    {
        path[nod] = path[heaviest_child];
        paths[path[nod]].push_back(nod);

        for (auto it = neigh[nod].begin(); it != neigh[nod].end(); ++it)
        {
            if (*it == heaviest_child || level[*it] < level[nod])
            {
                continue;
            }

            path_parent[path[*it]] = nod;
        }
    }
}

void build_segtree(int nd, int left, int right, int offset, int path)
{
    if (left == right)
    {
        segtree[nd + offset] = v[paths[path][left - 1]];
    }
    else
    {
        int mid = (left+right)/2;
        build_segtree(nd*2, left, mid, offset, path);
        build_segtree(nd*2+1, mid+1, right, offset, path);

        segtree[nd + offset] = std::max(segtree[nd*2+offset], segtree[nd*2+1+offset]);
    }
}

void update(int nd, int left, int right, int pos, int val, int offset)
{
    if (left == right)
    {
        segtree[nd + offset] = val;
    }
    else
    {
        int mid = (left+right)/2;
        if (pos <= mid)
        {
            update(2*nd, left, mid, pos, val, offset);
        }
        else
        {
            update(2*nd+1, mid+1, right, pos, val, offset);
        }

        segtree[nd + offset] = std::max(segtree[2*nd+offset], segtree[2*nd+1+offset]);
    }
}

int query(int nd, int left, int right, int qleft, int qright, int offset)
{
    int ans = 0;
    
    if (left >= qleft && right <= qright)
    {
        ans = segtree[nd + offset];
    }
    else
    {
        int mid = (left+right)/2;
        if (qleft <= mid)
        {
            ans = query(nd*2, left, mid, qleft, qright, offset);
        }
        if (qright > mid)
        {
            ans = std::max(ans, query(nd*2+1, mid+1, right, qleft, qright, offset));
        }
    }

    return ans;
}

int main()
{
    freopen("heavypath.in", "r", stdin);
    freopen("heavypath.out", "w", stdout);
    scanf("%d%d", &N, &M);
    for (int i = 1; i <= N; ++i)
    {
        scanf("%d", &v[i]);
    }

    for (int i = 0; i < N-1; ++i)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        neigh[a].push_back(b);
        neigh[b].push_back(a);
    }

    level[1] = 1;
    dfs(1);

    for (int i = 1; i <= last_path; ++i)
    {
        reverse(paths[i].begin(), paths[i].end());
        if (i > 1)
        {
            st_offsets[i] = st_offsets[i-1] + paths[i-1].size() * 4;
        }

        build_segtree(1, 1, paths[i].size(), st_offsets[i], i);
    }

    for (int i = 0; i < M; ++i)
    {
        int t, x, y;
        scanf("%d%d%d", &t, &x, &y);

        if (t == 0)
        {
            update(1,1,paths[path[x]].size(), level[x]-level[paths[path[x]][0]]+1, 
                    y, st_offsets[path[x]]); 
        }
        else
        {
            int sol = 0;
            while (true)
            {
                if (path[x] == path[y])
                {
                    if (level[x] > level[y])
                    {
                        std::swap(x,y);
                    }

                    sol = std::max(sol, query(1, 1, paths[path[x]].size(), 
                                level[x] - level[paths[path[x]][0]] + 1,
                                level[y] - level[paths[path[x]][0]] + 1,
                                st_offsets[path[x]]));
                    break;
                }

                if (level[paths[path[x]][0]] < level[paths[path[y]][0]])
                {
                    std::swap(x, y);
                }

                    sol = std::max(sol, query(1, 1, paths[path[x]].size(), 1,
                                level[x] - level[paths[path[x]][0]] + 1,
                                st_offsets[path[x]]));
                    x = path_parent[path[x]];
            }

            printf("%d\n", sol);
        }
    }

    return 0;
}