Cod sursa(job #2043959)

Utilizator Stefan_RaduStefan Radu Stefan_Radu Data 20 octombrie 2017 19:47:06
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.41 kb
#include <fstream>
#include <vector>
#include <algorithm>
#include <bitset>

using namespace std;

ifstream cin("heavypath.in");
ofstream cout("heavypath.out");
  
const int MAX_N = 1e5 + 7;

vector < int > val_of(MAX_N);
vector < vector < int > > gr(MAX_N);
vector < int > root_of(MAX_N);
vector < int > level_of(MAX_N);
vector < int > rank_of(MAX_N);
vector < int > chain_nr(MAX_N);
vector < int > poz_of(MAX_N);
vector < vector < int > > chain;
bitset < MAX_N > used;

class Segment_tree {

public:
  Segment_tree(int n, int chain_nr) {
    _n = n;
    _chain_nr = chain_nr;
    _arb.resize(n << 2);
    _Init(1, n, 1);
  }

  void Update(int poz, int val) {
    _Update(val, poz, 1, _n, 1);
  }

  int Query(int l, int r) {
    return _Query(l, r, 1, _n, 1);
  }

private:
  int _n;
  int _chain_nr;
  vector < int > _arb;

  int _Init(int st, int dr, int cur_node) {
    if (st == dr) {
      _arb[cur_node] = val_of[chain[_chain_nr][st]];
      return _arb[cur_node];
    }

    int mid = (st + dr) >> 1;
    _arb[cur_node] = max(_Init(st, mid, cur_node << 1), 
      _Init(mid + 1, dr, cur_node << 1 | 1));

    return _arb[cur_node];
  }

  void _Update(int val, int poz, int st, int dr, int cur_node) {
    if (st == dr) {
      _arb[cur_node] = val;
      return ;
    }

    int mid = (st + dr) >> 1;
    int left = cur_node << 1;
    int right = cur_node << 1 | 1;
    if (poz <= mid) {
      _Update(val, poz, st, mid, left);
    }
    else {
      _Update(val, poz, mid + 1, dr, right);
    }

    _arb[cur_node] = max(_arb[left], _arb[right]);
  }

  int _Query(int l, int r, int st, int dr, int cur_node) {
    if (l <= st and dr <= r) {
      return _arb[cur_node];
    }

    int mid = (st + dr) >> 1;
    int left = -1;
    int right = -1;
    if (l <= mid) {
      left = _Query(l, r, st, mid, cur_node << 1);
    }
    if (mid + 1 <= r) {
      right = _Query(l, r, mid + 1, dr, cur_node << 1 | 1);
    }

    return max(left, right);
  }
};

int Dfs(int cur_node, int cur_level, int &cnt) {
  
  used[cur_node] = true;
  int best_rank = -1;
  bool went_on = false;
  level_of[cur_node] = cur_level;
  rank_of[cur_node] = 1;
  for (auto next_node : gr[cur_node]) {
    if (used[next_node]) {
      continue;
    }

    went_on = true;
    root_of[next_node] = cur_node;
    int next_rank = Dfs(next_node, cur_level + 1, cnt);
    if (next_rank > best_rank) {
      chain_nr[cur_node] = chain_nr[next_node];
      best_rank = next_rank;
    } 
    rank_of[cur_node] += next_rank;
  }

  if (not went_on) {
    chain_nr[cur_node] = ++ cnt;
    return 1;
  }

  return rank_of[cur_node];
}

void Init(int n, int &cnt) {

  for (int i = 1; i <= n; i ++) {
    cin >> val_of[i];
  }

  for (int i = 1; i < n; i ++) {
    int x, y;
    cin >> x >> y;
    gr[x].push_back(y);
    gr[y].push_back(x);
  }
  
  root_of[1] = 1;
  rank_of[1] = Dfs(1, 1, cnt);
}

void Make_chains(int n, int cnt) {
 
  for (int i = 1; i <= n; i ++) {
    int ch_nr = chain_nr[i];
    if (not chain[ch_nr].size()) {
      chain[ch_nr].push_back(-27);
    }
    chain[ch_nr].push_back(i);
  }

  for (int i = 1; i <= cnt; i ++) {
    sort(chain[i].begin() + 1, chain[i].end(), [] (const int a, const int b) -> bool {
      return level_of[a] < level_of[b];
    });

    for (int j = 1; j < chain[i].size(); j ++) {
      poz_of[chain[i][j]] = j;
    }
  }
}

int get_top_level(int x) {
  return level_of[chain[x][1]];
}

int get_root(int x) {
  return root_of[chain[x][1]];
}

int main(int argc, char const *argv[]) {
  
  int n, m;
  cin >> n >> m;

  int cnt = 0;
  Init(n, cnt);  
    
  chain.resize(cnt + 1);
  Make_chains(n, cnt);

  vector < Segment_tree* > Tree(cnt + 1);
  for (int i = 1; i <= cnt; i ++) {
    Tree[i] = new Segment_tree(chain[i].size() - 1, i);
  }

  for (int i = 1; i <= m; i ++) {
    int t, x, y;
    cin >> t >> x >> y;

    int ch_nr;
    if (not t) {
      ch_nr = chain_nr[x];
      int poz = poz_of[x]; 
      Tree[ch_nr] -> Update(poz, y);
      continue;
    }

    int sol = -1;
    while (chain_nr[x] != chain_nr[y]) {
      int a = get_top_level(chain_nr[x]);
      int b = get_top_level(chain_nr[y]);

      if (a < b) {
        swap(x, y);
      }

      ch_nr = chain_nr[x];
      sol = max(sol, Tree[ch_nr] -> Query(1, poz_of[x]));
      x = get_root(ch_nr);
    }

    ch_nr = chain_nr[x];
    int poz1 = poz_of[x];
    int poz2 = poz_of[y];
    if (poz1 > poz2) {
      swap(poz1, poz2);
    }

    sol = max(sol, Tree[ch_nr] -> Query(poz1, poz2));
    cout << sol << '\n';
  }
}