Cod sursa(job #2044149)

Utilizator AlexandruValeanuAlexandru Valeanu AlexandruValeanu Data 20 octombrie 2017 22:50:38
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.43 kb
#include <bits/stdc++.h>

using namespace std;

int combine(int x, int y){
  return max(x, y);
}

class SegmentTree{
private:

  vector<int> tree;
  int N;

  void build(const vector<int> &that){
    for (int i = 0; i < N; i++){
      tree[i + N] = that[i];
    }

    for (int i = N - 1; i > 0; i--)
      tree[i] = combine(tree[2 * i], tree[2 * i + 1]);
  }

public:

  SegmentTree(const vector<int> &that){
    N = (int)that.size();
    tree.resize(2 * N);
    build(that);
  }

  void update(int pos, int key){
    pos += N;
    tree[pos] = key;

    while (pos > 1){
      tree[pos / 2] = combine(tree[pos], tree[pos ^ 1]);
      pos /= 2;
    }
  }

  int query(int l, int r) const{
    l += N; r += N;
    r++;

    int result = numeric_limits<int>::min() / 2;

    while (l < r){
      if (l & 1){
        result = max(result, tree[l]);
        l++;
      }

      if (r & 1){
        r--;
        result = max(result, tree[r]);
      }

      l /= 2;
      r /= 2;
    }

    return result;
  }
};

constexpr int MAX = 100000;

using Graph = vector<vector<int>>;

template<size_t MAX>
using Array = array<int, MAX>;

Graph graph;
Array<MAX> father, depth, size_subtree;
Array<MAX> length_path, pos_in_path, path, start_node;

vector<SegmentTree> segtrees;
vector<int> keys;

int num_paths;

void dfs(int node){
  int heavy_son = -1;
  size_subtree[node] = 1;

  for (int v: graph[node]){
    if (father[v] == -1){
      father[v] = node;
      depth[v] = depth[node] + 1;
      dfs(v);
      size_subtree[node] += size_subtree[v];

      if (heavy_son == -1 || size_subtree[heavy_son] < size_subtree[v])
        heavy_son = v;
    }
  }

  if (heavy_son == -1)
    path[node] = ::num_paths++;
  else
    path[node] = path[heavy_son];

  pos_in_path[node] = length_path[path[node]]++;
}

void build_heavy_paths(int N){
  fill(father.begin(), father.begin() + N, -1);

  father[0] = 0;
  dfs(0);

  for (int i = 0; i < N; i++){
    pos_in_path[i] = length_path[path[i]] - pos_in_path[i] - 1;

    if (pos_in_path[i] == 0)
      start_node[path[i]] = i;
  }

  vector<vector<int>> all_keys(num_paths);

  for (int i = 0; i < ::num_paths; i++)
    all_keys[i].resize(length_path[i]);

  for (int i = 0; i < N; i++)
    all_keys[path[i]][pos_in_path[i]] = keys[i];

  for (int i = 0; i < ::num_paths; i++)
    segtrees.push_back(SegmentTree(all_keys[i]));
}

void update(int node, int new_key){
  segtrees[path[node]].update(pos_in_path[node], new_key);
}

int query(int x, int y){
  if (depth[start_node[path[x]]] < depth[start_node[path[y]]])
    swap(x, y);

  if (path[x] == path[y])
    return segtrees[path[x]].query(min(pos_in_path[x], pos_in_path[y]),
                                   max(pos_in_path[x], pos_in_path[y]));
  else return combine(segtrees[path[x]].query(0, pos_in_path[x]),
                      query(father[start_node[path[x]]], y));
}

int main(){
  ios_base::sync_with_stdio(false);

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

  int N, Q;
  cin >> N >> Q;

  keys.resize(N);
  for (int &x: keys)
    cin >> x;

  graph.resize(N);

  for (int i = 0; i < N - 1; i++){
    int u, v;
    cin >> u >> v;
    u--; v--;

    graph[u].push_back(v);
    graph[v].push_back(u);
  }

  build_heavy_paths(N);

  while (Q--){
    int t;
    cin >> t;

    if (t == 0){
      int x, k;
      cin >> x >> k;
      x--;

      update(x, k);
    }
    else{
      int x, y;
      cin >> x >> y;
      x--; y--;
      cout << query(x, y) << "\n";
    }
  }

  return 0;
}