Cod sursa(job #1490659)

Utilizator salam1Florin Salam salam1 Data 23 septembrie 2015 22:13:32
Problema Heavy Path Decomposition Scor 10
Compilator cpp Status done
Runda Arhiva educationala Marime 4.38 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];

// Tree related info
int lvl[NMAX];
bool mark[NMAX];
int noChildren[NMAX], par[NMAX];

// chains related structs
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;
  noChildren[node] = 1;
  for (auto x: G[node])
    if (!mark[x]) {
      lvl[x] = lvl[node] + 1;
      par[x] = node;
      dfs(x);
      noChildren[node] += noChildren[x];
    }
}

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 = noChildren[x];
      bestChild = x;
    }
  }

  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 constructChains() {
  dfs(1);

  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 getLca(int x, int y) {
  while (whatChain[x] != whatChain[y]) {
    int chainIdx = whatChain[y];
    if (lvl[x] > lvl[y]) {
      x = parentPathSplit[whatChain[x]];
    } else {
      y = parentPathSplit[whatChain[y]];
    }
  }

  return lvl[x] < lvl[y] ? x : y;
}

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));
}

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();
  constructChains();
  solve();
  return 0;
}