Cod sursa(job #1490266)

Utilizator salam1Florin Salam salam1 Data 23 septembrie 2015 01:22:58
Problema Heavy Path Decomposition Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 5.02 kb
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;

const int NMAX = 100505;
const int LMAX = (1LL << 18);
const int HMAX = 19;
const int INF = 0x3f3f3f3f;

int n, m, val[NMAX];
vector<int> G[NMAX];

// LCA related structs
int euler[LMAX], firstPos[NMAX], r;
int lvl[NMAX], lg[LMAX], minInterval[HMAX][LMAX];
bool mark[NMAX];

// chains related structs
int noChildren[NMAX], par[NMAX];
int whatChain[NMAX], whatPos[NMAX], parentPathSplit[NMAX];
vector<int> Paths[NMAX], PathsArb[NMAX];
int noChains;

void read() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++) {
    scanf("%d", &val[i]);
  }
  int x, y;
  for (int i = 1; i < n; i++) {
    scanf("%d%d", &x, &y);
    G[x].push_back(y); G[y].push_back(x);
  }
}

void dfs(int node) {
  mark[node] = true;
  euler[++r] = node; firstPos[node] = r;
  noChildren[node] = 1;
  for (auto x: G[node])
    if (!mark[x]) {
      lvl[x] = lvl[node] + 1; par[x] = node;
      dfs(x);
      euler[++r] = node;
      noChildren[node] += noChildren[x];
    }
}

inline int minLevel(int node1, int node2) {
  return lvl[node1] < lvl[node2] ? node1 : node2;
}

void constructLCAStruct() {
  dfs(1);

  for (int i = 1; i <= r; i++) {
    minInterval[0][i] = euler[i];
    lg[i] = i > 1 ? lg[i >> 1] + 1 : 0;
  }

  for (int step = 1; (1 << step) <= r; step++) {
    for (int i = 1; i <= r - (1 << step) + 1; i++) {
      minInterval[step][i] = minLevel(
        minInterval[step - 1][i],
        minInterval[step - 1][i + (1 << (step - 1))]);
    }
  }
}

int getLca(int node1, int node2) {
  node1 = firstPos[node1];
  node2 = firstPos[node2];
  if (node1 > node2) swap(node1, node2);

  int l = lg[node2 - node1 + 1];
  return minLevel(minInterval[l][node1], minInterval[l][node2 - (1 << l) + 1]);
}

void addToLatestChain(int node) {
  Paths[noChains - 1].push_back(node);
  whatChain[node] = noChains - 1;
  whatPos[node] = Paths[noChains - 1].size() - 1;
}

void dfs2(int node) {
  if (noChildren[node] == 1) return ;

  int bestChild = -1, bestChildValue = 0;
  for (auto x: G[node]) {
    if (par[x] == node && noChildren[x] > bestChildValue) {
      bestChildValue = x;
      bestChild = x;
    }
  }

  //printf("GO %d SIZE %d\n", node, Paths.size());

  addToLatestChain(bestChild);
  dfs2(bestChild);

  for (auto x: G[node]) {
    if (par[x] == node && x != bestChild) {
      noChains++;
      addToLatestChain(x);
      parentPathSplit[noChains - 1] = node;
      dfs2(x);
    }
  }
}

void cstrSegmentTree(vector<int>& path, vector<int>& arb, int left, int right, int node) {
  if (left == right) {
    arb[node] = val[path[left]];
    return ;
  }
  int mid = (left + right) / 2;
  cstrSegmentTree(path, arb, left, mid, node * 2);
  cstrSegmentTree(path, arb, mid + 1, right, node * 2 + 1);
  arb[node] = max(arb[node * 2], arb[node * 2 + 1]);
}

void updateSingle(vector<int>& arb, int left, int right, int pos, int newVal, int node) {
  if (left == right) {
    arb[node] = newVal;
    return ;
  }
  int mid = (left + right) / 2;
  if (pos <= mid)
    updateSingle(arb, left, mid, pos, newVal, node * 2);
  else
    updateSingle(arb, mid + 1, right, pos, newVal, node * 2 + 1);

  arb[node] = max(arb[node * 2], arb[node * 2 + 1]);
}

int getMaxInterval(vector<int>& arb, int left, int right, int l, int r, int node) {
  if (r < left || right < l) {
    return -INF;
  }
  if (l <= left && right <= r)
    return arb[node];
  int mid = (left + right) / 2;
  return max(
    getMaxInterval(arb, left, mid, l, r, node * 2),
    getMaxInterval(arb, mid + 1, right, l, r, node * 2 + 1));
}

void constructChains() {
  memset(mark, false, sizeof(mark));
  noChains++;
  addToLatestChain(1);
  dfs2(1);

  // cstr segment trees
  for (size_t i = 0; i < noChains; i++) {
    // infer size of the segment tree for currrent path
    int size = Paths[i].size(), step;
    for (step = 1; step <= size; step <<= 1);
    PathsArb[i].reserve(step * 2 + 1);

    cstrSegmentTree(Paths[i], PathsArb[i], 0, size - 1, 1);
  }
}

int getMaxAncestorPath(int x, int y) {
  int ret = val[x];
  while (x != y) {
    int chainIdx = whatChain[y];
    if (whatChain[x] != whatChain[y]) {
      ret = max(ret, getMaxInterval(
        PathsArb[chainIdx], 0, Paths[chainIdx].size() - 1, 0, whatPos[y], 1));
      y = parentPathSplit[chainIdx];  
    } else {
      ret = max(ret, getMaxInterval(
        PathsArb[chainIdx], 0, Paths[chainIdx].size() - 1, whatPos[x], whatPos[y], 1));
      y = x;
    }
  }

  return ret;
}

void solve() {
  int type, x, y;

  while (m--) {
    scanf("%d%d%d", &type, &x, &y);
    switch (type) {
      case 0: {
        val[x] = y;
        int chainIdx = whatChain[x];
        updateSingle(PathsArb[chainIdx], 0, Paths[chainIdx].size() - 1, whatPos[x], y, 1);
        break;
      }
      case 1: {
        int lca = getLca(x, y);
        printf("%d\n", max(getMaxAncestorPath(lca, x), getMaxAncestorPath(lca, y)));
        break ;
      }
    }
  }
}

int main() {
  freopen("heavypath.in", "r", stdin);
  freopen("heavypath.out", "w", stdout);

  read();
  constructLCAStruct();
  constructChains();
  solve();
  return 0;
}