Cod sursa(job #2417259)

Utilizator GoogalAbabei Daniel Googal Data 29 aprilie 2019 13:00:34
Problema Heavy Path Decomposition Scor 80
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.27 kb
#include <algorithm>
#include <iostream>
#include <memory.h>
#include <fstream>
#include <cassert>
#include <vector>
#include <array>

using namespace std;

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

const int NMAX = 1e5;

int n, m, nrc;

int levelg[1 + NMAX];
int parent[1 + NMAX];
int cno[1 + NMAX];
int cpos[1 + NMAX];
int ni[1 + NMAX];
int ssz[1 + NMAX];
int v[1 + NMAX];

vector < int > g[1 + NMAX];
vector < int > chain[1 + NMAX];
vector < int > aint[1 + NMAX];

void dfs(int node, int p) {
  vector < int > :: iterator to;
  levelg[node] = levelg[p] + 1;
  ssz[node] = 1;

  if(g[node].size() == 1) {
    nrc++;
    chain[nrc].push_back(node);
    cno[node] = nrc;
    //cpos[node] = chain[nrc].size() - 1;
    return;
  }

  int sszm = -1;
  int chn;

  for(to = g[node].begin(); to != g[node].end(); to++) {
    if(*to == p)
      continue;
    dfs(*to, node);
    ssz[node] += ssz[*to];
    parent[*to] = node;
    if(sszm < ssz[*to]) {
      sszm = ssz[*to];
      chn = cno[*to];
    }
  }

  assert(0 <= sszm);
  chain[chn].push_back(node);
  cno[node] = chn;
  //cpos[node] = chain[chn].size() - 1;
}

void update(int nr, int i) {
  if(0 < i) {
    aint[nr][i] = aint[nr][2 * i];
    if(v[aint[nr][i]] < v[aint[nr][2 * i + 1]])
      aint[nr][i] = aint[nr][2 * i + 1];
    update(nr, i / 2);
  }
}

void makeaint(int nr) {
  int exp = 0;
  int sz = chain[nr].size();

  for(int i = 0; i <= 5 * sz + 10; i++)
    aint[nr].push_back(0);

  while((1 << exp) < sz)
    exp++;
  ni[nr] = (1 << exp) - 1;

  for(int i = 0; i < chain[nr].size(); i++) {
    aint[nr][ni[nr] + i + 1] = chain[nr][i];
    //cout << ni + i + 1 << ' ' << aint[nr][ni + i + 1] << '\n' ;
    update(nr, (ni[nr] + i + 1) / 2);
  }


  /*
  cout << nr << "     ";
  for(int i = 1; i <= 4 * chain[nr].size(); i++)
    cout << aint[nr][i] << ' ';
  cout << '\n';
  */
}

void build() {
  g[1].push_back(0);
  dfs(1, 0);

  for(int i = 1; i <= nrc; i++) {
    reverse(chain[i].begin(), chain[i].end());
    for(int j = 0; j < chain[i].size(); j++)
      cpos[chain[i][j]] = j;
  }

  /*
  for(int i = 1; i <= nrc; i++) {
    for(int j = 0; j < chain[i].size(); j++) {
      cout << chain[i][j] << ' ';
    }
    cout << '\n';
  }
{1}
  for(int i = 1; i <= n; i++)
    cout << cpos[i] << ' ';
  cout << '\n';
  */

  for(int i = 1; i <= nrc; i++)
    makeaint(i);
}

int aintquery(int nr, int from, int to) {
  int ans = 0;
  if(from == to) {
    ans = aint[nr][from];
  } else if(to > from) {
    if(from % 2 == 1) {
      if(v[ans] < v[aint[nr][from]])
        ans =  aint[nr][from];
      from++;
    }

    if(to % 2 == 0) {
      if(v[ans] < v[aint[nr][to]])
      ans = aint[nr][to];
      to--;
    }

    int pretender = aintquery(nr, from / 2, to / 2);
    if(v[ans] < v[pretender])
      ans = pretender;
  }
  return ans;
}

int main()
{
  in >> n >> m;
  for(int i = 1; i <= n; i++)
    in >> v[i];
  for(int i = 1; i < n; i++) {
    int x, y;
    in >> x >> y;
    g[x].push_back(y);
    g[y].push_back(x);
  }

  build();

  for(int i = 1; i <= m; i++) {
    int op, x, y;
    in >> op >> x >> y;
    if(op == 0) {
      int cch = cno[x];
      v[x] = y;

      update(cch, (ni[cch] + cpos[x] + 1) / 2);

    } else if(op == 1) {
      int cx = cno[x];
      int cy = cno[y];
      int stx = chain[cx][0];
      int sty = chain[cy][0];
      int res = 0;

      while(1) {
        if(cx == cy) {
          if(cpos[x] > cpos[y])
            swap(x, y);
          int pretender = aintquery(cx, ni[cx] + cpos[x] + 1, ni[cy] + cpos[y] + 1);

          if(v[res] < v[pretender])
            res = pretender;
          out << v[res] << '\n';
          break;
        } else {
          if(levelg[parent[stx]] < levelg[parent[sty]]) {
            swap(stx, sty);
            swap(cx, cy);
            swap(x, y);
          }

          int pretender = aintquery(cx, ni[cx] + 1, ni[cx] + cpos[x] + 1);

          if(v[res] < v[pretender])
            res = pretender;
          x = parent[stx];
          cx = cno[x];
          stx = chain[cx][0];
        }
      }
    } else {
      assert(0);
    }

  }

  in.close();
  out.close();

  return 0;
}