Cod sursa(job #3288076)

Utilizator Nasa1004Ema Nicole Gheorghe Nasa1004 Data 20 martie 2025 14:22:57
Problema Heavy Path Decomposition Scor 80
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.87 kb
#include <fstream>
#include <algorithm>
#include <vector>

using namespace std;
const int NMAX = 100002;
const int LOG = 18;

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

vector <vector <int>> adj;

struct noduri {
    int val; ///val init pe care o are nodul, pt queryuri
    int tata;
    int depth;

    short int weight; ///cate lanturi (inclusiv el)sunt sub el
    int lant; ///in ce lant apartine

    int pos; ///pozitia in vectorul sortat
}v[NMAX];

vector <int> l;///primul, cel mai de sus din lant
int topo[NMAX]; ///ord nodurilor dupa lanturi si depth

int up[NMAX][LOG + 1];

void dfs(int start) {
    bool ok = 0;
    for(auto nod : adj[start]) {
        if(nod == v[start].tata)
            continue;
        v[nod].tata = start;
        v[nod].depth = v[start].depth + 1;

        up[nod][0] = start; ///binary liftingul
        for(int j = 1; j < LOG; j++)
            up[nod][j] = up[up[nod][j - 1]][j - 1];

        dfs(nod);
        ok = 1;
    }
    if(!ok) { ///frunza, init un lant
        l.push_back(start);
        v[start].lant = l.size() - 1;
        v[start].weight = 1; ///ca are doar un lant
        return;
    }
    int maxx = 0, cnt = 0;
    for(auto nod : adj[start]) { ///gasim copilul cu nr de lanturi maxim
        if(nod == v[start].tata)
            continue;
        if(v[nod].weight > maxx) {
            maxx = v[nod].weight;
            cnt = 1;
        }
        else if(v[nod].weight == maxx)
            cnt++;
    }
    ///noi ne unim cu copilul respectiv, dar oricum cautam
    ///nrmax de lanturi de sub el (de pe o ramura), deci:
    ///- dc sunt mai multe maxuri, o sa fie maxx + 1
    ///- dc e doar un max, adunci e max(maxx, urm cel mai mare + 1),
    ///deci tot max

    if(cnt > 1)
        v[start].weight = maxx + 1;
    else
        v[start].weight = maxx;

    for(auto nod : adj[start]) { ///ne unim cu un lant
        if(nod == v[start].tata)
            continue;
        if(v[nod].weight == maxx) {
            v[start].lant = v[nod].lant;
            l[v[start].lant] = start; ///updatam si in lant
            break;
        }
    }
}

bool cmp(int a, int b) { ///pt sortarea topo
    if(v[a].lant != v[b].lant)
        return v[a].lant < v[b].lant;
    return v[a].depth < v[b].depth;
}

int LCA(int a, int b) {
    if(v[a].depth < v[b].depth)
        swap(a, b);
    int k = v[a].depth - v[b].depth;
    for(int j = LOG - 1; j >= 0; j--) {
        if(k & (1 << j))
            a = up[a][j];
    }
    if(a == b)
        return a;
    for(int j = LOG - 1; j >= 0; j--) {
        if(up[a][j] != up[b][j]) {
            a = up[a][j];
            b = up[b][j];
        }
    }
    return up[a][0];
}


int aint[4 * NMAX];
void build(int nod, int st, int dr) {
    if(st == dr) {
        aint[nod] = v[topo[st]].val;
        return;
    }
    int mid = (st + dr) / 2;
    build(2 * nod, st, mid);
    build(2 * nod + 1, mid + 1, dr);
    aint[nod] = max(aint[2 * nod], aint[2 * nod + 1]);
}
void update(int nod, int st, int dr, int pos, int val) {
    if(st == dr) {
        aint[nod] = val;
        return;
    }
    int mid = (st + dr) / 2;
    if(pos <= mid)
        update(2 * nod, st, mid, pos, val);
    else
        update(2 * nod + 1, mid + 1, dr, pos, val);
    aint[nod] = max(aint[2 * nod], aint[2 * nod + 1]);
}
int query(int nod, int st, int dr, int pos1, int pos2) {
    if(st == pos1 && dr == pos2)
        return aint[nod];
    int ans = -1;
    int mid = (st + dr) / 2;
    if(pos1 <= mid)
        ans = query(2 * nod, st, mid, pos1, min(mid, pos2));
    if(mid < pos2)
        ans = max(ans, query(2 * nod + 1, mid + 1, dr, max(mid + 1, pos1), pos2));
    return ans;
}

int n;
int solvepath(int a, int b) { ///a-ul e ala de mai JOS
    //cout << "parti " << a << " " << b << '\n';
    if(v[a].lant == v[b].lant) ///super tare, query pe aint
        return query(1, 1, n, v[b].pos, v[a].pos);
    int ans = query(1, 1, n, v[l[v[a].lant]].pos, v[a].pos);
    a = v[l[v[a].lant]].tata;
    ans = max(ans, solvepath(a, b));
    return ans;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int m;
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        cin >> v[i].val;
    adj.resize(n + 1);
    for(int i = 1; i < n; i++) {
        int a, b;
        cin >> a >> b;
        adj[a].push_back(b);
        adj[b].push_back(a);
    }
    v[1].tata = 0;
    dfs(1);
    adj.clear();

    for(int i = 1; i <= n; i++)
        topo[i] = i;
    sort(topo + 1, topo + n + 1, cmp);
    for(int i = 1; i <= n; i++) { ///updatam pt fiec pozitia noua din sir
        v[topo[i]].pos = i;
        //cout << topo[i] << " ";
    }

    build(1, 1, n);
    /*for(int i = 1; i <= n; i++)
        for(int j = i; j <= n; j++)
            cout << i << " " << j << "  " << query(1, 1, n, i, j) << '\n';*/
    /*for(int i = 1; i <= n; i++) {
        for(int j = 0; j < LOG; j++)
            cout << up[i][j] << " ";
        cout << '\n';
    }*/
    while(m--) {
        int tip, x, y;
        cin >> tip >> x >> y;
        if(tip == 0) ///update --> v[x].val = y
            update(1, 1, n, v[x].pos, y);
        else { ///query pe lantul (x, y)
            int lca = LCA(x, y);
            //cout << lca << '\n';
            int ans = 0;
            if(lca == x || lca == y) {
                if(x == lca)
                    swap(x, y);
                ans = solvepath(x, y);
            }
            else
                ans = max(solvepath(x, lca), solvepath(y, lca));
            cout << ans << '\n';
        }
    }


    /*cout << '\n';
    for(int i = 1; i <= n; i++)
        cout << i << " " << v[i].weight << " " << v[i].lant << '\n';
    cout << '\n';
    for(int i = 0; i < l.size(); i++)
        cout << i << " " << l[i].first << " " << l[i].last << '\n';*/
    return 0;
}