Cod sursa(job #2264931)

Utilizator MoodyFaresFares Mohamad MoodyFares Data 20 octombrie 2018 13:07:31
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.38 kb
#include <cstdio>
#include <vector>
#include <algorithm>

const int MAX_N = 100000;

class SegmentTree {
public:
  int value;
  int leftIndex;
  int rightIndex;
  SegmentTree* left;
  SegmentTree* right;
  
  void update(int pos, int newValue) {
    int size = (int)(rightIndex - leftIndex);
    if (size == 1) {
      value = newValue;
      return;
    }
    if (pos < leftIndex + size / 2)
      left->update(pos, newValue);
    else
      right->update(pos, newValue);
    value = std::max(left->value, right->value);
  }
  
  int query(int leftQ, int rightQ) {
    int size = (int)(rightIndex - leftIndex);
    if (leftQ <= leftIndex && rightIndex <= rightQ)
      return value;
    int tempAns = 0;
    if (leftQ < leftIndex + size / 2)
      tempAns = std::max(tempAns, left->query(leftQ, rightQ));
    if (rightQ - 1 >= leftIndex + size / 2)
      tempAns = std::max(tempAns, right->query(leftQ, rightQ));
    return tempAns;
  }
};

struct Path {
  std::vector<int> nodes;
  SegmentTree* root;
  
  Path() {
    root = NULL;
  }
};

struct Range {
  int high;
  int low;
  // high <= low
  
  Range() {
    high = MAX_N;
    low = 0;
  }
  
  Range(int _high, int _low) {
    high = _high;
    low = _low;
  }
};

int a[1 + MAX_N];
std::vector<int> tree[1 + MAX_N];
Path paths[1 + MAX_N];
int subTree[1 + MAX_N];
int level[1 + MAX_N];
int path[1 + MAX_N];
int posInPath[1 + MAX_N];
Range range[1 + MAX_N];
int dad[1 + MAX_N];
int leaves;

SegmentTree* buildSegmentTree(std::vector<int>::iterator begin, std::vector<int>::iterator end, int leftIndex, int rightIndex) {
  int size = (int)(end - begin);
  if (size == 1)
    return new SegmentTree {a[*begin], leftIndex, rightIndex, NULL, NULL};
  SegmentTree* left = buildSegmentTree(begin, begin + size / 2, leftIndex, leftIndex + size / 2);
  SegmentTree* right = buildSegmentTree(begin + size / 2, end, leftIndex + size / 2, rightIndex);
  int value = std::max(left->value, right->value);
  return new SegmentTree {value, leftIndex, rightIndex, left, right};
}

void dfs(int v, int last = 0) {
  subTree[v] = 1;
  dad[v] = last;
  level[v] = level[last] + 1;
  int biggestSon = 0;
  for (auto u : tree[v]) {
    if (u != last) {
      dfs(u, v);
      subTree[v] += subTree[u];
      if (subTree[biggestSon] < subTree[u])
        biggestSon = u;
    }
  }
  if (biggestSon == 0)
    path[v] = ++leaves;
  else
    path[v] = path[biggestSon];
  paths[path[v]].nodes.push_back(v);
  posInPath[v] = (int)paths[path[v]].nodes.size();
  range[path[v]] = Range(std::min(range[path[v]].high, level[v]), std::max(range[path[v]].low, level[v]));
}

int main() {
  freopen("heavypath.in", "r", stdin);
  freopen("heavypath.out", "w", stdout);
  
  int n, m;
  scanf("%d%d", &n, &m);
  
  for (int i = 1; i <= n; i++)
    scanf("%d", &a[i]);
  for (int i = 1; i <= n - 1; i++) {
    int u, v;
    scanf("%d%d", &u, &v);
    tree[u].push_back(v);
    tree[v].push_back(u);
  }
  
  dfs(1);
  for (int i = 1; i <= leaves; i++)
    paths[i].root = buildSegmentTree(paths[i].nodes.begin(), paths[i].nodes.end(), 1, (int)paths[i].nodes.size() + 1);
  
  for (int i = 1; i <= m; i++) {
    int t, x, y;
    scanf("%d%d%d", &t, &x, &y);
    if (t == 0) {
      paths[path[x]].root->update(posInPath[x], y);
    } else {
      int ans = 0;
      while (x != y) {
        if (level[x] < level[y])
          std::swap(x, y);
        if (level[x] > level[y]) { // x e mai jos
          while (range[path[x]].high > level[y]) {
            int size = (int)paths[path[x]].nodes.size();
            ans = std::max(ans, paths[path[x]].root->query(posInPath[x], size + 1));
            x = dad[paths[path[x]].nodes[size -  1]];
          }
          ans = std::max(ans, paths[path[x]].root->query(posInPath[x], posInPath[x] + level[x] - level[y] + 1));
          x = paths[path[x]].nodes[posInPath[x] - 1 + level[x] - level[y]];
        } else {
          int sizeX = (int)paths[path[x]].nodes.size();
          int sizeY = (int)paths[path[y]].nodes.size();
          if (level[dad[paths[path[x]].nodes[sizeX -  1]]] > level[dad[paths[path[y]].nodes[sizeY -  1]]]) {
            ans = std::max(ans, paths[path[x]].root->query(posInPath[x], sizeX + 1));
            x = dad[paths[path[x]].nodes[sizeX -  1]];
          } else {
            ans = std::max(ans, paths[path[y]].root->query(posInPath[y], sizeY + 1));
            y = dad[paths[path[y]].nodes[sizeY -  1]];
          }
        }
      }
      printf("%d\n", ans);
    }
  }
  return 0;
}