Cod sursa(job #2632718)

Utilizator gabrielinelusGabriel-Robert Inelus gabrielinelus Data 4 iulie 2020 15:10:29
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.03 kb
#include <cstdio>
#include <algorithm>
#include <vector>
#include <climits>

using namespace std;
vector<int> value; // value[k] -> the value of the k'th node.

class SegmentTree2{
 public:

  void Build(vector<int> *v)
  {
    data_.resize( ( ((int)v->size()) <<2) |1);
    treeSize_= v->size();
    Build_(0, treeSize_ - 1, 0, v);
  }

  void Update(int pos, int val)
  {
    Update_(0, treeSize_-1, 0, pos, val); 
  }

  int Query(int left, int right)
  {
    return Query_(0, treeSize_-1, 0, left, right);
  }

 private:
  void Build_(int li, int lf, int pz, vector<int> *v)
  {
    if (li == lf) {
      data_[pz] = value[(*v)[li]];
      return;
    }
    int m = li + ((lf - li) / 2);
    Build_(li, m, (pz<<1)|1, v);
    Build_(m + 1, lf, (pz+1)<<1, v);
    data_[pz] = max(data_[(pz<<1)|1], data_[(pz+1)<<1]);
  }

  bool Update_(int li, int lf, int pz, int &pos, int &val)
  {
    if (li == lf) {
      data_[pz] = val;
      return true;
    }
    int m = li + ((lf - li) >> 1);
    if (pos <= m) Update_(li, m, (pz<<1)|1, pos, val);
    else Update_(m + 1, lf, (pz+1)<<1, pos, val);
    data_[pz] = max(data_[(pz<<1)|1], data_[(pz+1)<<1]);
  }

  int Query_(int li, int lf, int pz, int &left, int &right)
  {
    if (left <= li && lf <= right)
      return data_[pz];
    int m = li + ((lf - li) >> 1);
    int answer = -1;
    if (left <= m) answer = max(answer, Query_(li, m, (pz<<1)|1, left, right));
    if (right > m ) answer = max(answer, Query_(m + 1, lf, (pz+1)<<1, left, right));
    return answer;
  }

  int treeSize_;
  vector<int> data_;
};


class SegmentTree{
 public:
  SegmentTree() = default;
  void Build(const vector<int>& elem)
  {
    data_.resize(elem.size() * 4 + 1);
    size_ = elem.size();
    Build_(0, size_-1, 0, elem);
  }
  void Update(int index, int newValue)
  {
    Update_(0, size_-1, 0, index, newValue);
  }
  int Query(int A, int B)
  {
    int answer = numeric_limits<int>::min();
    Query_(0, size_-1, 0, A, B, answer);
    return answer;
  }  
 private:
  void Build_(int li, int lf, int pz, const vector<int>& elem)
  {
    if (li == lf) {
      data_[pz] = value[elem[li]];
      return;
    }
    int m = li + ((lf-li)>>1);
    Build_(li, m, (pz<<1)|1, elem);
    Build_(m+1, lf, (pz+1)<<1, elem);
    data_[pz] = max(data_[(pz<<1)|1], data_[(pz+1)<<1]); 
  }
  void Update_(int li, int lf, int pz, int index, int newValue)
  {
    if (li == lf) {
      data_[pz] = newValue;
      return;
    }
    int m = li + ((lf-li)>>1);
    if (index <= m)
      Update_(li, m, (pz<<1)|1, index, newValue);
    else
      Update_(m+1, lf, (pz+1)<<1, index, newValue);
    data_[pz] = max(data_[(pz<<1)|1], data_[(pz+1)<<1]);
  }
  void Query_(int li, int lf, int pz, int &A, int &B, int& answer)
  {
    if (A <= li && lf <= B) {
      answer = max(answer, data_[pz]);
      return;
    }
    int m = li + ((lf - li) >> 1);
    if (A <= m)
      Query_(li, m, (pz<<1)|1, A, B, answer);
    if (B > m)
      Query_(m+1, lf, (pz+1)<<1, A, B, answer);
  }
  vector<int> data_;
  int size_;
};

vector<vector<int>> Graph;
vector<int> depth; // depth[k] -> the depth of the k'th node.
vector<int> weight; // weight[k] -> the number of nodes in k'th node's subtree (including k).
vector<bool> used; // used[k] -> whether we visited k'th node.
vector<vector<int>> paths; // paths[k] -> k'th path of the heavy path decoposition
vector<int> whichPath; // whichPath[k] -> in which path is the k'th node
vector<int> pathPosition; // pathPosition[k] -> what's the index of the k'th node in its path
vector<int> pathsDaddy; // pathsDaddy[k] -> which node is k'th path's parent?
vector<SegmentTree2> SegmentTrees; // SegmentTrees[k] -> segment tree for the k'th path
int N, M;

void ReadData()
{
  scanf("%d%d", &N, &M);

  Graph.resize(N, vector<int>());
  value.resize(N);
  depth.resize(N);
  weight.resize(N);
  used.resize(N);
  whichPath.resize(N);
  pathPosition.resize(N);
  
  for (int i = 0; i < N; ++i)
    scanf("%d", &value[i]);
  for (int i = 0; i < N - 1; ++i) {
    int x, y;
    scanf("%d%d", &x, &y);
    --x; --y;
    Graph[x].emplace_back(y);
    Graph[y].emplace_back(x);
  }
}

void GetWeight(int k)
{
  used[k] = 1;
  for (auto it: Graph[k])
    if (!used[it]) {
      depth[it] = depth[k] + 1;
      GetWeight(it);
      weight[k] += weight[it];
    }
  weight[k] += 1;
}

void heavy(int k)
{
  used[k] = true;
  paths[(int)paths.size()-1].emplace_back(k);
  whichPath[k] = (int)paths.size()-1;
  pathPosition[k] = paths[whichPath[k]].size() - 1;
  for (auto it: Graph[k]) {
    if (!used[it]) {
      if (paths.back().back() != k) {
	paths.emplace_back(vector<int>());
	pathsDaddy.emplace_back(k);
      }
      heavy(it);
    }
  }
}

void Decompose()
{
  GetWeight(0);
  fill(used.begin(), used.end(), false);
  for (int i = 0; i < N; ++i)
    for (int j = 1; j < Graph[i].size(); ++j)
      if (weight[Graph[i][0]] < weight[Graph[i][j]])
	swap(Graph[i][0], Graph[i][j]);

  paths.emplace_back(vector<int>());
  pathsDaddy.emplace_back(-1);
  heavy(0);
}

void BuildSegmentTrees()
{
  SegmentTrees.resize(paths.size());
  for (int i = 0; i < paths.size(); ++i)
    SegmentTrees[i].Build(&paths[i]);
}

void Solve()
{
  int x, y, op;
  for (int i = 0; i < M; ++i) {
    scanf("%d%d%d", &op, &x, &y);
    --x;
    if (op == 0) {
      SegmentTrees[whichPath[x]].Update(pathPosition[x], y);
      continue;
    }
    --y;
    int answer = numeric_limits<int>::min();
    while (whichPath[x] != whichPath[y]) {
      if (depth[pathsDaddy[whichPath[x]]] < depth[pathsDaddy[whichPath[y]]])
	swap(x,y);
      // x is the deepest
      if (whichPath[x] == 0) // this is the parent path
	swap(x, y);
      // x must be on a lower path
      //answer = max(answer, SegmentTrees[whichPath[x]].Query(0, pathPosition[x]));
      x = pathsDaddy[whichPath[x]];
    }
    if (pathPosition[x] > pathPosition[y])
      swap(x, y);
    answer = max(answer, SegmentTrees[whichPath[x]].Query(pathPosition[x], pathPosition[y]));
    printf("%d\n", answer);
  }
}

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

  ReadData();
  Decompose();
  BuildSegmentTrees();
  Solve();
  
  return 0;
}