Cod sursa(job #2685812)

Utilizator popashtefan10Popa Stefan popashtefan10 Data 17 decembrie 2020 19:17:06
Problema Heavy Path Decomposition Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.33 kb
#include <iostream>
#include <cstdio>
#include <vector>

using namespace std;

const int LOGN = 16;
const int NMAX = 100000;

int n, m, euler_idx;
int val[NMAX + 5], first_ap[NMAX + 5], h[NMAX + 5];
int path[NMAX + 5], path_poz[NMAX + 5];
int rmq[LOGN][2 * NMAX + 5];
vector<int> arb[NMAX + 5], path_dad;
vector<vector<int>> paths, aints;

void dfs(int nod, int dad) {
  h[nod] = h[dad] + 1;
  first_ap[nod] = ++euler_idx;
  rmq[0][euler_idx] = nod;

  for(int vec: arb[nod])
    if(vec != dad) {
      dfs(vec, nod);
      rmq[0][++euler_idx] = nod;
    }
}

int get_log2(int x) {
  int log2 = 0;
  while(x > 1) x >>= 1, log2++;
  return log2;
}

void calc_rmq() {
  euler_idx = 0;
  dfs(1, 0);

  for(int l = 2; l <= euler_idx; l *= 2)
    for(int i = 1; i + l - 1 <= euler_idx; i++) {
      int log2 = get_log2(l), nod_st = rmq[log2 - 1][i], nod_dr = rmq[log2 - 1][i + l / 2];
      rmq[log2][i] = (h[nod_st] < h[nod_dr]) ? nod_st : nod_dr;
    }
}

int get_lca(int nod1, int nod2) {
  int f1 = first_ap[nod1], f2 = first_ap[nod2];
  if(f1 > f2) swap(f1, f2);

  int l = f2 - f1 + 1, log2 = get_log2(l);
  int nst = rmq[log2][f1], ndr = rmq[log2][f2 - l + 1];
  return (h[nst] < h[ndr]) ? nst : ndr;
}

int path_decomposition(int nod, int dad) {
  bool frunza = true;
  int path_length = 0, heaviest = -1;

  for(int vec: arb[nod])
    if(vec != dad) {
      frunza = false;
      int vec_length = path_decomposition(vec, nod);

      if(vec_length + 1 > path_length) {
        path_length = vec_length + 1;
        heaviest = path[vec];
      }
    }

  if(!frunza) {
    paths[heaviest].push_back(nod);
    path[nod] = heaviest;
    path_poz[nod] = paths[heaviest].size() - 1;

    for(int vec: arb[nod])
      if(vec != dad && path[vec] != heaviest)
        path_dad[path[vec]] = nod;
  }
  else {
    vector<int> new_path;
    paths.push_back(new_path);
    paths.back().push_back(nod);

    path_dad.push_back(0);
    path[nod] = paths.size() - 1;
    path_poz[nod] = 0;
  }

  return path_length;
}

void update(vector<int> &aint, int nod, int nst, int ndr, int upoz, int val) {
  if(nst > ndr || upoz < nst || upoz > ndr) return;
  if(nst == ndr) {
    aint[nod] = val;
    return;
  }

  int mij = (nst + ndr) / 2;
  if(upoz <= mij)
    update(aint, 2 * nod, nst, mij, upoz, val);
  else
    update(aint, 2 * nod + 1, mij + 1, ndr, upoz, val);
  aint[nod] = max(aint[2 * nod], aint[2 * nod + 1]);
}

int qaint(vector<int> &aint, int nod, int nst, int ndr, int qst, int qdr) {
  if(nst > ndr || qst > ndr || qdr < nst) return 0;
  if(nst >= qst && ndr <= qdr) return aint[nod];

  int mij = (nst + ndr) / 2;
  int q1 = qaint(aint, 2 * nod, nst, mij, qst, qdr);
  int q2 = qaint(aint, 2 * nod + 1, mij + 1, ndr, qst, qdr);
  return max(q1, q2);
}

int query(int nod1, int nod2) {
  int ans = 0, lca = get_lca(nod1, nod2);

  while(path[nod1] != path[lca]) {
    int p = path[nod1], psz = paths[p].size();
    ans = max(ans, qaint(aints[p], 1, 0, psz - 1, path_poz[nod1], psz - 1));
    nod1 = path_dad[p];
  }
  while(path[nod2] != path[lca]) {
    int p = path[nod2], psz = paths[p].size();
    ans = max(ans, qaint(aints[p], 1, 0, psz - 1, path_poz[nod2], psz - 1));
    nod2 = path_dad[p];
  }

  int p = path[lca], poz1 = path_poz[nod1], poz2 = path_poz[nod2];
  if(poz1 > poz2) swap(poz1, poz2);
  ans = max(ans, qaint(aints[p], 1, 0, paths[p].size() - 1, poz1, poz2));
  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", &val[i]);
  for(int i = 1; i < n; i++) {
    int x, y;
    scanf("%d %d", &x, &y);
    arb[x].push_back(y);
    arb[y].push_back(x);
  }

  calc_rmq();
  path_decomposition(1, 0);

  for(int i = 0; i < paths.size(); i++) {
    vector<int> new_aint;
    aints.push_back(new_aint);
    aints[i].resize(4 * paths[i].size(), 0);

    for(int j = 0; j < paths[i].size(); j++)
      update(aints[i], 1, 0, paths[i].size() - 1, j, val[paths[i][j]]);
  }

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

    if(t == 0)
      update(aints[path[x]], 1, 0, paths[path[x]].size() - 1, path_poz[x], y);
    else
      printf("%d\n", query(x, y));
  }

  return 0;
}