Cod sursa(job #3172402)

Utilizator cata00Catalin Francu cata00 Data 20 noiembrie 2023 16:27:00
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.89 kb
// Same as v2, but does away with node depths. Uses node DFS pos for
// comparisons. Simplifies the decision of which path to climb, as follows.
//
// The original code compares the depths of n[u].head and n[v].head. But
// comparing the DFS times is enough. What we want is to ensure that, once u
// is on the common path, it will wait for v there. Note that, if u is on the
// common path and v is not, then necessarily n[v].pos > n[u].pos, because u
// is on a heavy path and v is not. And heavy children are always called
// before light ones.
#include <stdio.h>

const int MAX_NODES = 1 << 17;

struct cell {
  int v, next;
};

struct node {
  int adj;
  int val;
  int parent;
  int heavy;  // the child with the largest subtree
  int head;   // the top of our path
  int pos;    // DFS time
};

int next_power_of_2(int n) {
  while (n & (n - 1)) {
    n += n & -n;
  }
  return n;
}

int max(int x, int y) {
  return (x > y) ? x : y;
}

struct segment_tree {
  int v[2 * MAX_NODES];
  int n;

  void init(node* n, int num_nodes) {
    this->n = next_power_of_2(num_nodes);
    for (int u = 1; u <= num_nodes; u++) {
      v[n[u].pos + this->n] = n[u].val;
    }
    for (int pos = this->n - 1; pos; pos--) {
      v[pos] = max(v[2 * pos], v[2 * pos + 1]);
    }
  }

  void update(int pos, int val) {
    pos += n;
    v[pos] = val;
    for (pos /= 2; pos; pos /= 2) {
      v[pos] = max(v[2 * pos], v[2 * pos + 1]);
    }
  }

  int rmq(int l, int r) {
    int result = -1;

    l += n;
    r += n;

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

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

    return result;
  }
};

cell list[2 * MAX_NODES];
node n[MAX_NODES + 1];
segment_tree segtree;
int num_nodes, num_queries;
FILE *fin, *fout;

void add_edge(int u, int v) {
  static int pos = 1;
  list[pos] = { v, n[u].adj };
  n[u].adj = pos++;
}

void read_input_data() {
  fin = fopen("heavypath.in", "r");
  fout = fopen("heavypath.out", "w");

  fscanf(fin, "%d %d", &num_nodes, &num_queries);
  for (int u = 1; u <= num_nodes; u++) {
    fscanf(fin, "%d", &n[u].val);
  }

  for (int i = 0; i < num_nodes - 1; i++) {
    int u, v;
    fscanf(fin, "%d %d", &u, &v);
    add_edge(u, v);
    add_edge(v, u);
  }
}

int heavy_dfs(int u) {
  int my_size = 1, max_child_size = 0;

  for (int ptr = n[u].adj; ptr; ptr = list[ptr].next) {
    int v = list[ptr].v;
    if (v != n[u].parent) {

      n[v].parent = u;
      int child_size = heavy_dfs(v);
      my_size += child_size;
      if (child_size > max_child_size) {
        max_child_size = child_size;
        n[u].heavy = v;
      }

    }
  }

  return my_size;
}

void decompose_dfs(int u, int head) {
  static int time = 0;

  n[u].head = head;
  n[u].pos = time++;

  if (n[u].heavy) {
    decompose_dfs(n[u].heavy, head);
  }

  for (int ptr = n[u].adj; ptr; ptr = list[ptr].next) {
    int v = list[ptr].v;
    if (v != n[u].parent && v != n[u].heavy) {
      decompose_dfs(v, v); // start a new path
    }
  }
}

int query(int u, int v) {
  int result = 0;
  while (n[u].head != n[v].head) {
    if (n[v].pos > n[u].pos) {
      int tmp = u; u = v; v = tmp;
    }
    result = max(result, segtree.rmq(n[n[u].head].pos, n[u].pos));
    // Jumping to the head's *parent* puts us on a new path.
    u = n[n[u].head].parent;
  }

  // The last query happens on the common path.
  if (n[u].pos > n[v].pos) {
    int tmp = u; u = v; v = tmp;
  }
  result = max(result, segtree.rmq(n[u].pos, n[v].pos));

  return result;
}

void process_queries() {
  while (num_queries--) {
    int t, x, y;
    fscanf(fin, "%d %d %d", &t, &x, &y);
    if (t) {
      fprintf(fout, "%d\n", query(x, y));
    } else {
      segtree.update(n[x].pos, y);
    }
  }

  fclose(fin);
  fclose(fout);
}

int main() {
  read_input_data();
  heavy_dfs(1);
  decompose_dfs(1, 1);
  segtree.init(n, num_nodes);
  process_queries();

  return 0;
}