Cod sursa(job #2986362)

Utilizator iraresmihaiiordache rares mihai iraresmihai Data 28 februarie 2023 13:06:15
Problema Heavy Path Decomposition Scor 40
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.27 kb
#include <iostream>
#include <vector>

#define MAXN 100000
#define LOG_MAXN 20
using namespace std;

struct node{
  int chain, posInChain, parent, heavyChild;
  int s, lvl, firstApp, val;
  vector <int> neighbours;
};

node tree[MAXN];
vector <int> aint[MAXN];
vector <int> chains[MAXN];
int euler[MAXN * 2];
int eulerSize;
int chainSize;
int rmq[2 * MAXN][LOG_MAXN];
int lg[2 * MAXN + 1];

void precalcLg() {
  int i;

  for ( i = 2; i <= 2 * MAXN; i++ ) {
    lg[i] = lg[i / 2] + 1;
  }
}

void dfs1(int pos) {
  euler[eulerSize] = pos;
  eulerSize++;
  tree[pos].firstApp = eulerSize - 1;
  tree[pos].s = 1;
  tree[pos].heavyChild = -1;
  for ( int v : tree[pos].neighbours ) {
    if ( tree[pos].parent != v ) {
      tree[v].parent = pos;
      tree[v].lvl = tree[pos].lvl + 1;
      dfs1(v);
      euler[eulerSize] = pos;
      eulerSize++;
      tree[pos].s += tree[v].s;
      if ( tree[pos].heavyChild == -1 || tree[tree[pos].heavyChild].s < tree[v].s ) {
        tree[pos].heavyChild = v;
      }
    }
  }
}

void dfs2(int pos, int chain) {
  chains[chain].push_back(pos);
  tree[pos].chain = chain;
  tree[pos].posInChain = chains[chain].size() - 1;

  for ( int v : tree[pos].neighbours ) {
    if ( v != tree[pos].parent ) {
      if ( v == tree[pos].heavyChild ) {
        dfs2(v, chain);
      } else {
        chainSize++;
        dfs2(v, chainSize);
      }
    }
  }
}

void buildRmq() {
  int i, i2;

  precalcLg();

  for ( i = 0; i < eulerSize; i++ ) {
    rmq[i][0] = euler[i];
  }

  for ( i2 = 1; (1 << i2) <= eulerSize; i2++ ) {
    for ( i = 0; i + (1 << i2) + 1 <= eulerSize; i++ ) {
      if ( tree[rmq[i][i2 - 1]].lvl < tree[rmq[i + (1 << (i2 - 1))][i2 - 1]].lvl ) {
        rmq[i][i2] = rmq[i][i2-  1];
      } else {
        rmq[i][i2] = rmq[i + (1 << (i2 - 1))][i2 - 1];
      }
    }
  }
}

void initialiseAint(int aintPos) {
  int s;

  s = chains[aintPos].size() * 2;
  while ( s-- ) {
    aint[aintPos].push_back(0);
  }
}

void buildAint(int aintPos, int l, int r, int n) {
  if ( l == r ) {
    aint[aintPos][n] = tree[chains[aintPos][l]].val;
    return;
  }

  int nSt, nDr, mij;
  mij = (l + r) / 2;
  nSt = n + 1;
  nDr = n + 2 * (mij - l + 1);

  buildAint(aintPos, l, mij, nSt);
  buildAint(aintPos, mij + 1, r, nDr);

  aint[aintPos][n] = max(aint[aintPos][nSt], aint[aintPos][nDr]);
}

int queryAint(int aintPos, int qL, int qR, int l, int r, int n) {
  if ( qL <= l && r <= qR ) {
    return aint[aintPos][n];
  }

  int nSt, nDr, mij, ans;
  mij = (l + r) / 2;
  nSt = n + 1;
  nDr = n + 2 * (mij - l + 1);

  ans = 0;
  if ( qL <= mij ) {
    ans = max(ans, queryAint(aintPos, qL, qR, l, mij, nSt));
  }
  if ( mij < qR ) {
    ans = max(ans, queryAint(aintPos, qL, qR, mij + 1, r, nDr));
  }

  return ans;
}

void updateAint(int aintPos, int pos, int l, int r, int n) {
  if ( l == r ) {
    aint[aintPos][n] = tree[chains[aintPos][l]].val;
    return;
  }

  int nSt, nDr, mij;
  mij = (l + r) / 2;
  nSt = n + 1;
  nDr = n + 2 * (mij - l + 1);

  if ( pos <= mij ) {
    updateAint(aintPos, pos, l, mij, nSt);
  } else {
    updateAint(aintPos, pos, mij + 1, r, nDr);
  }

  aint[aintPos][n] = max(aint[aintPos][nSt], aint[aintPos][nDr]);
}

int lca(int a, int b) {
  int len;

  a = tree[a].firstApp;
  b = tree[b].firstApp;
  if ( a > b ) {
    swap(a, b);
  }

  len = b - a + 1;
  if ( tree[rmq[a][lg[len]]].lvl < tree[rmq[b - (1 << lg[len]) + 1][lg[len]]].lvl ) {
    return rmq[a][lg[len]];
  }
  return rmq[b - (1 << lg[len]) + 1][lg[len]];
}

int queryForChain(int start, int finish) {
  int pos, ans;

  if ( tree[start].lvl < tree[finish].lvl ) {
    swap(start, finish);
  }

  pos = start;
  ans = 0;
  while ( tree[pos].chain != tree[finish].chain ) {
    ans = max(ans, queryAint(tree[pos].chain, 0, tree[pos].posInChain, 0, chains[tree[pos].chain].size() - 1, 0));
    pos = tree[chains[tree[pos].chain][0]].parent;
  }
  ans = max(ans, queryAint(tree[pos].chain, tree[finish].posInChain, tree[pos].posInChain, 0, chains[tree[pos].chain].size() - 1, 0));

  return ans;
}

int mainQuery(int a, int b) {
  int upNode;

  upNode = lca(a, b);

  return max(queryForChain(a, upNode), queryForChain(b, upNode));
}

void addEdge(int a, int b) {
  tree[a].neighbours.push_back(b);
  tree[b].neighbours.push_back(a);
}

int main() {
  FILE *fin, *fout;
  fin = fopen("heavypath.in", "r");
  fout = fopen("heavypath.out", "w");

  int n, q, i, t, a, b;

  fscanf(fin, "%d%d", &n, &q);

  for ( i = 0; i < n; i++ ) {
    fscanf(fin, "%d", &tree[i].val);
  }

  for ( i = 0; i < n - 1; i++ ) {
    fscanf(fin, "%d%d", &a, &b);
    a--;
    b--;

    addEdge(a, b);
  }

  eulerSize = 0;
  chainSize = 0;
  dfs1(0);
  dfs2(0, chainSize);
  buildRmq();

  for ( i = 0; i <= chainSize; i++ ) {
    initialiseAint(i);
    buildAint(i, 0, chains[i].size() - 1, 0);
  }

  while ( q-- ) {
    fscanf(fin, "%d%d%d", &t, &a, &b);
    a--;

    if ( t ) {
      b--;
      fprintf(fout, "%d\n", mainQuery(a, b));
    } else {
      tree[a].val = b;
      updateAint(tree[a].chain, tree[a].posInChain, 0, chains[tree[a].chain].size() - 1, 0);
    }
  }

  fclose(fin);
  fclose(fout);

  return 0;
}