Cod sursa(job #2022810)

Utilizator Mihai_PredaPreda Mihai Dragos Mihai_Preda Data 17 septembrie 2017 13:16:41
Problema Heavy Path Decomposition Scor 60
Compilator cpp Status done
Runda Arhiva educationala Marime 5.92 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <cassert>
#include <cstdio>

using namespace std;

const int nMax = 100005;
const int logMax = 20;
const int INF = (1 << 30);

class arbint
{
public:
    arbint(int sz)
    {
        n = sz;
        int lg = ceil(log2(n));
        arb = new int[1 << lg + 1];
    }
    inline void Update(int ind, int val)
    {
        Update(ind, val, 1, 1, n);
    }
    inline int MaxQuery(int start, int finish)
    {
        return MaxQuery(start, finish, 1, n, 1);
    }
private:
    int *arb;
    int n;

    void Update(int ind, int val, int nod, int st, int dr)
    {
        if(st == dr)
        {
            arb[nod] = val;
            return;
        }
        int mid = (st + dr) / 2;
        if(ind <= mid)
            Update(ind, val, nod * 2, st, mid);
        else
            Update(ind, val, nod * 2 + 1, mid + 1, dr);
        arb[nod] = max(arb[nod*2], arb[nod*2+1]);
    }

    int MaxQuery(int start, int finish, int st, int dr, int nod = 1)
    {
        if(start <= st && finish >= dr)
            return arb[nod];
        int mid = (st + dr) / 2;
        int ret = -INF;
        if(start <= mid)
            ret = max(ret, MaxQuery(start, finish, st, mid, nod * 2));
        if(finish > mid)
            ret = max(ret, MaxQuery(start, finish, mid + 1, dr, nod * 2 + 1));
        return ret;
    }
};

struct lant
{
    lant()
    {
        noduri.push_back(0);
    }
    ~lant()
    {
    }
    vector<int> noduri;
    arbint *aint;
    int lastNod;
    void UpdateAll()
    {
        aint = new arbint(noduri.size() - 1);
        for(int i = 1; i < noduri.size(); ++i)
            aint->Update(i, noduri[i]);
    }
    inline void Update(int ind, int val)
    {
        aint->Update(ind, val);
    }
    inline int MaxQuery(int start, int finish)
    {
        return aint->MaxQuery(start, finish);
    }
    void Test()
    {
    }
};

class arbore
{
public:
    arbore(int n)
    {
        this->n = n;
        vecini.resize(n + 1);
        val.resize(n + 1);
        lantNr.resize(n + 1);
        lantPos.resize(n + 1);
        heavy.resize(n + 1);
        nivel.resize(n + 1);
        for(int i = 0; i < logMax; ++i)
            father[i].resize(n + 1);
    }
    void AddEdge(int x, int y)
    {
        vecini[x].push_back(y);
        vecini[y].push_back(x);
    }
    void BuildPath()
    {
        DFS(1, 1);
        for(int i = 0; i < lanturi.size(); ++i)
            lanturi[i].UpdateAll();
        for(int i = 1; (1 << i) <= n; ++i)
            for(int j = 1; j <= n; ++j)
                father[i][j] = father[i-1][father[i-1][j]];
    }
    void Update(int ind, int value)
    {
        val[ind] = value;
        lanturi[lantNr[ind]].Update(lantPos[ind], value);
    }
    int Query(int x, int y)
    {
        int lca = GetLCA(x, y);
        return max(QueryLCA(lca, x), QueryLCA(lca, y));
    }
    vector<int> val;
private:
    int n;
    vector<vector<int> > vecini;
    vector<int> lantNr;
    vector<int> lantPos;
    vector<lant> lanturi;
    vector<int> heavy;
    vector<int> father[logMax];
    vector<int> nivel;

    int QueryLCA(int lca, int y)
    {
        int x = lca;
        int ret = val[x];
        while(x != y)
        {
            if(lantNr[x] == lantNr[y])
            {
                ret = max(ret, lanturi[lantNr[x]].MaxQuery(lantPos[y], lantPos[x]));
                y = x;
            }
            else
            {
                ret = max(ret, lanturi[lantNr[y]].MaxQuery(lantPos[y], lanturi[lantNr[y]].noduri.size() - 1));
                y = father[0][lanturi[lantNr[y]].lastNod];
            }
        }
        return ret;
    }

    void DFS(int current, int fth)
    {
        father[0][current] = fth;
        nivel[current] = nivel[fth] + 1;
        if(current != 1 && vecini[current].size() == 1)
        {
            lant x;
            x.noduri.push_back(val[current]);
            x.lastNod = current;
            lanturi.push_back(x);
            lantNr[current] = lanturi.size() - 1;
            lantPos[current] = 1;
            heavy[current] = 1;
            return;
        }
        for(auto v:vecini[current])
            if(v != fth)
                DFS(v, current);
        int maxHeavy = 0, ind;
        for(auto v:vecini[current])
            if(v != fth)
            {
                heavy[current] += heavy[v];
                if(heavy[v] > maxHeavy)
                {
                    maxHeavy = heavy[v];
                    ind = v;
                }
            }
        lantNr[current] = lantNr[ind];
        lanturi[lantNr[current]].noduri.push_back(val[current]);
        lanturi[lantNr[current]].lastNod = current;
        lantPos[current] = lantPos[ind] + 1;
    }

    int GetLCA(int x, int y)
    {
        if(nivel[x] < nivel[y])
            swap(x, y);
        int step;
        for(step = 0; (1 << step) < n; ++step);
        for(int i = step; i >= 0; --i)
            if(nivel[father[i][x]] >= nivel[y])
                x = father[i][x];
        if(x == y)
            return x;
        for(int i = step; i >= 0; --i)
            if(father[i][x] != father[i][y])
                x = father[i][x], y = father[i][y];
        return father[0][x];
    }
};

int main()
{
    int n, m;
    freopen("heavypath.in", "r", stdin);
    freopen("heavypath.out", "w", stdout);
    scanf("%d %d", &n, &m);
    arbore arb(n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &(arb.val[i]));
    int a, b;
    for(int i = 1; i < n; ++i)
    {
        scanf("%d %d", &a, &b);
        arb.AddEdge(a, b);
    }
    arb.BuildPath();
    int t, x, y;
    while(m--)
    {
        scanf("%d %d %d", &t, &x, &y);
        if(t == 0)
            arb.Update(x, y);
        else
            printf("%d\n", arb.Query(x, y));
    }
    return 0;
}