Cod sursa(job #2838270)

Utilizator LaserDenisCrismariu Denis LaserDenis Data 23 ianuarie 2022 12:17:04
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.16 kb
#include <bits/stdc++.h>

using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int rand(int a, int b)
{
    int ans = uniform_int_distribution<int>(a, b)(rng);
    return ans;
}
#define fastio std::ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
#define test " test "
#define yes "YES"
#define no "NO"
#define bn '\n'
#define ll long long
#define pb push_back
#define all(x) x.begin(), x.end()
//#define int long long
#define deb(a) cout << #a << "=" << (a) << bn
#define deb2(a, b) cout << #a << "=" << (a) << " " << #b << "=" << b << bn
#define readV(v, n)             \
    for (int i = 0; i < n; i++) \
        cin >> v[i];
#define printV(v)    \
    for (auto i : v) \
        cout << i << " ";
#define FILES                      \
    freopen("txt.in", "r", stdin); \
    freopen("txt.out", "w", stdout);
const int mod = 1e9 + 7;
const int NMAX = 1e5 + 10;
int maxi = INT_MIN, mini = INT_MAX;
int n, q, fr;
int v[NMAX], dp[NMAX], tatal[NMAX], nivel[NMAX];
int lnt[NMAX];
int pos[NMAX];
vector<vector<int>> lant;
vector<vector<int>> tree;
vector<int> adj[NMAX];
void dfs(int node, int tata);
void dfs2(int node, int tata);
void build(int node, int st, int dr, int id);
void update(int node, int st, int dr, int pos, int val, int id);
int query(int node, int st, int dr, int x, int y, int id);
void solve()
{
    cin >> n >> q;
    int a, b;
    for (int i = 1; i <= n; i++)
        cin >> v[i];

    for (int i = 1; i < n; i++)
    {
        cin >> a >> b;
        adj[b].pb(a);
        adj[a].pb(b);
    }
    dfs(1, 0);

    lant.resize(n + 1);
    tree.resize(n + 1);
    fr = 0;
    dfs2(1, 0);
    for (int i = 1; i <= fr; i++)
    {
        tree[i].resize(4 * lant[i].size() + 5);
        build(1, 1, lant[i].size(), i);
    }
    // cout << test;
    int x, y, c;
    while (q--)
    {
        cin >> c >> x >> y;
        int idx = lnt[x], idy = lnt[y];
        if (c == 0)
        {
            update(1, 1, lant[idx].size(), pos[x], y, lnt[x]);
            continue;
        }
        int ans = 0;
        while (idx != idy)
        {
            idx = lnt[x];
            idy = lnt[y];
            if (nivel[lant[idx].back()] > nivel[lant[idy].back()])
            { // find max from x -> root of chain
                ans = max(ans, query(1, 1, lant[idx].size(), pos[x], lant[idx].size(), idx));
                /// x= tatal root chain
                x = tatal[lant[idx].back()];
                idx = lnt[x];
            }
            else
            {
                ans = max(ans, query(1, 1, lant[idy].size(), pos[y], lant[idy].size(), idy));
                y = tatal[lant[idy].back()];
                idy = lnt[y];
            }
        }
        if (nivel[x] < nivel[y])
        {
            swap(x, y);
        }
        idx = lnt[x];
        idy = lnt[y];
        ans = max(ans, query(1, 1, lant[idx].size(), pos[x], pos[y], idx));
        cout << ans << bn;
    }
}
void dfs(int node, int tata)
{
    nivel[node] = nivel[tata] + 1;
    tatal[node] = tata;
    dp[node] = 1;
    for (auto &it : adj[node])
        if (it != tata)
        {
            dfs(it, node);
            dp[node] += dp[it];
        }
    if (dp[node] == 1)
        fr++;
}
void dfs2(int node, int tata)
{
    for (auto &it : adj[node])
        if (it != tata)
            dfs2(it, node);
    if (dp[node] == 1)
    {
        lnt[node] = ++fr;  ///  id-ul lantului
        lant[fr].pb(node); /// adaug un node in lant
        pos[node] = 1;     // node-ul frunza este primul
        return;
    }
    int best = -1, newNode;
    for (auto it : adj[node])
        if (it != tata and best < dp[it])
        {
            best = dp[it];
            newNode = it;
        }
    /// adaugam la lantul copilului cu cel mai mare dp
    int id = lnt[newNode];
    lnt[node] = id;
    lant[id].pb(node);
    pos[node] = lant[id].size();
}
void build(int node, int st, int dr, int id)
{
    if (st == dr)
    { //-1, st=1,dr=.size()
        tree[id][node] = v[lant[id][st - 1]];
        return;
    }
    int mid = (st + dr) >> 1;
    build(node << 1, st, mid, id);
    build((node << 1) + 1, mid + 1, dr, id);
    tree[id][node] = max(tree[id][node << 1], tree[id][(node << 1) + 1]);
}
void update(int node, int st, int dr, int pos, int val, int id)
{
    if (st == dr)
    {
        tree[id][node] = val;
        return;
    }
    int mid = (st + dr) >> 1;
    if (pos <= mid)
        update(node << 1, st, mid, pos, val, id);
    else
        update((node << 1) + 1, mid + 1, dr, pos, val, id);
    tree[id][node] = max(tree[id][node << 1], tree[id][(node << 1) + 1]);
}
int query(int node, int st, int dr, int x, int y, int id)
{
    if (x <= st and dr <= y)
        return tree[id][node];
    int mid = (st + dr) >> 1;
    int ans = 0;
    if (x <= mid)
        ans = query(node << 1, st, mid, x, y, id);
    if (y > mid)
        ans = max(ans, query((node << 1) + 1, mid + 1, dr, x, y, id));
    return ans;
}
signed main()
{
    fastio;
    FILES;
    int __t = 1;
    // cin >> __t;
    while (__t--)
        solve();

    return 0;
}