Cod sursa(job #2241146)

Utilizator dahaandreiDaha Andrei Codrin dahaandrei Data 14 septembrie 2018 22:56:04
Problema Heavy Path Decomposition Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 3.66 kb
#include <fstream>
#include <vector>
#include <algorithm>

using namespace std;

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

const int MAXN = 1e5;
const int MAXM = 1e5;
const int MAXVAL = 2e9;

int n, m;
vector<int> g[MAXN + 1];

class Node{
public :
  int val;
  int sub;
  int niv;
  int par;
  int pat;
  int pos;

  Node() {
    val = 0;
    sub = 0;
    niv = 0;
    par = 0;
    pat = 0;
    pos = 0;
  }
};

vector<Node> nodes;

class Path{
public :
  vector<int> P, T;
  int par;

  Path() {
    P.clear();
    T.clear();
    par = 0;
  }

  void update(int node, int st, int dr, int poz, int val) {
    if (st == dr) {
      T[node] = val;
      return;
    }
    int mij = (st + dr) / 2;
    if (poz <= mij) update(node << 1, st, mij, poz, val);
    else update((node << 1) | 1, mij + 1, dr, poz, val);
    T[node] = max(T[node << 1], T[(node << 1) | 1]);
  }

  int query(int node, int st, int dr, int a, int b) {
    if (a <= st && dr <= b) return T[node];
    int mij = (st + dr) / 2;
    int le = 0, ri = 0;
    if (a <= mij) le = query(node << 1, st, mij, a, b);
    if (mij < b) ri = query((node << 1) | 1, mij + 1, dr, a, b);
    return max(le, ri);
  }

  void addToPath(int node) {
    P.push_back(node);
  }

  void reversePathAndMakeTree() {
    reverse(P.begin(), P.end());
    T.resize(P.size() << 2);
    for (int i = 1; i <= P.size(); ++ i) {
      nodes[P[i - 1]].pos = i;
      update(1, 1, P.size(), nodes[P[i - 1]].pos, nodes[P[i - 1]].val);
    }
  }

  void showPath() {
    for (auto x : P)
      out << x << ' ';
    out << '\n';

    for (int i = 1; i <= P.size(); ++ i) out << query(1, 1, P.size(), i, i) << ' ';
    out << '\n';
  }

};

vector<Path> paths;

void makePaths(int node, int prev, int niv) {
  nodes[node].niv = niv;
  nodes[node].par = prev;

  int connect = 0, maxsub = 0;
  for (auto x : g[node]) {
    if (x == prev) continue;
    makePaths(x, node, niv + 1);
    nodes[node].sub += nodes[x].sub + 1;
    if (maxsub < nodes[x].sub + 1) {
      maxsub = nodes[x].sub;
      connect = x;
    }
  }

  if (connect) {
    nodes[node].pat = nodes[connect].pat;
    paths[nodes[node].pat].par = prev;
    paths[nodes[node].pat].addToPath(node);
  }
  else {
    Path aux;
    aux.addToPath(node);
    aux.par = prev;
    nodes[node].pat = paths.size();
    paths.push_back(aux);
  }
}

void reversePathsAndMakeTrees() {
  for (auto &x : paths)
    x.reversePathAndMakeTree();
}

void solve0(int a, int b) {
  nodes[a].val = b;
  paths[nodes[a].pat].update(1, 1, paths[nodes[a].pat].P.size(), nodes[a].pos, nodes[a].val);
}

int solve1(int a, int b) {
  if (nodes[paths[nodes[a].pat].par].niv < nodes[paths[nodes[b].pat].par].niv)
    return solve1(b, a);

  if (nodes[paths[nodes[a].pat].par].pat == nodes[b].pat)
    return max(paths[nodes[a].pat].query(1, 1, paths[nodes[a].pat].P.size(), 1, nodes[a].pos), paths[nodes[b].pat].query(1, 1, paths[nodes[b].pat].P.size(), 1, nodes[b].pos));
  else
    return max(paths[nodes[a].pat].query(1, 1, paths[nodes[a].pat].P.size(), 1, nodes[a].pos), solve1(paths[nodes[a].pat].par, b));
}

int main() {
  in >> n >> m;
  nodes.resize(n + 1);

  for (int i = 1; i <= n; ++ i) in >> nodes[i].val;
  for (int i = 1; i < n; ++ i) {
    int a, b;
    in >> a >> b;
    g[a].push_back(b);
    g[b].push_back(a);
  }

  makePaths(1, 1, 1);
  reversePathsAndMakeTrees();

  int t, a, b;
  for (int i = 1; i <= m; ++ i) {
    in >> t >> a >> b;
    if (t)
      out << solve1(a, b) << '\n';
    else
      solve0(a, b);
  }

//  for (auto x : paths) x.showPath();

  return 0;
}