Cod sursa(job #1795673)

Utilizator stoianmihailStoian Mihail stoianmihail Data 2 noiembrie 2016 19:43:35
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.39 kb
#include <stdio.h>
#include <stdlib.h>

#define MAX_N 100000
#define NIL -1

int **list;
int size[MAX_N + 1];
int val[MAX_N + 1];

template <int cmp(int, int)> class T {
private:
  int *tree;
  int n, ptr;

public:
  T() {

  }

private:
  void build(int u, int left, int right, const int get) {
    if (left == right) {
      this -> tree[u] = val[list[get][this -> ptr]];
      this -> ptr++;
      return;
    }

    int mid = (left + right) / 2;
    build(2 * u, left, mid, get);
    build(2 * u + 1, mid + 1, right, get);
    this -> tree[u] = cmp(this -> tree[2 * u], this -> tree[2 * u + 1]);
  }

  void update(int u, int left, int right, const int pos, const int val) {
    if (left == right) {
      this -> tree[u] = val;
      return;
    }

    int mid = (left + right) / 2;
    if (pos <= mid) {
      update(2 * u, left, mid, pos, val);
    } else {
      update(2 * u + 1, mid + 1, right, pos, val);
    }
    this -> tree[u] = cmp(this -> tree[2 * u], this -> tree[2 * u + 1]);
  }

  int query(int u, int left, int right, const int a, const int b) {
    if (a <= left && right <= b) {
      return this -> tree[u];
    }

    int mid = (left + right) / 2;
    int result = NIL;

    if (a <= mid) {
      result = cmp(result, query(2 * u, left, mid, a, b));
    }
    if (b > mid) {
      result = cmp(result, query(2 * u + 1, mid + 1, right, a, b));
    }
    return result;
  }
public:
  void init(int get) {
    this -> n = size[get];
    this -> ptr = 0;

    this -> tree = (int*)calloc(4 * n, sizeof(int));
    this -> build(1, 0, n - 1, get);
  }

  void update(int pos, int val) {
    update(1, 0, n - 1, pos, val);
  }

  int query(int a, int b) {
    return query(1, 0, n - 1, a, b);
  }
};

typedef struct {
  int v, next;
} cell;

int N, M;
int adj[MAX_N + 1];
cell l[2 * MAX_N];

int numPaths;
int d[MAX_N + 1];
int pos[MAX_N + 1];
int path[MAX_N + 1];
int count[MAX_N + 1];
int begin[MAX_N + 1];
int father[MAX_N + 1];

int MAX(int X, int Y) {
  return X > Y ? X : Y;
}

T <MAX> *tree;

void addEdge(int u, int v, int pos) {
  l[pos].v = v;
  l[pos].next = adj[u];
  adj[u] = pos;
}

void dfs(int u) {
  int v, ptr, son = 0;

  count[u] = 1;
  for (ptr = adj[u]; ptr; ptr = l[ptr].next) {
    v = l[ptr].v;
    if (father[v] == 0) {
      father[v] = u;
      d[v] = d[u] + 1;

      dfs(v);

      count[u] += count[v];
      if (count[v] > count[son]) {
        son = v;
      }
    }
  }
  if (son == 0) {
    path[u] = numPaths++;
  } else {
    path[u] = path[son];
  }
  pos[u] = size[path[u]]++;
}

void heavyPath() {
  // Parcurge in adancime arborele, afland caile.
  father[1] = 1;
  d[1] = 1;
  dfs(1);

  // Determina nodurile de start ale cailor.
  int u;
  for (u = 1; u <= N; u++) {
    pos[u] = size[path[u]] - pos[u] - 1;
    if (pos[u] == 0) {
      begin[path[u]] = u;
    }
  }
}

void makePaths() {
  int i, u;

  // Alocarea memoriei.
  list = (int**)calloc(numPaths, sizeof(int*));
  for (i = 0; i < numPaths; i++) {
    list[i] = (int*)calloc(size[i], sizeof(int));
    size[i] = 0;
  }

  // Aranjeaza path-urile.
  for (u = 1; u <= N; u++) {
    list[path[u]][size[path[u]]] = u;
    size[path[u]]++;
  }

  // Construieste arborii de intervale.
  tree = new T <MAX> [numPaths];
  for (i = 0; i < numPaths; i++) {
    tree[i].init(i);
  }
}

int getAnswer(int u, int v) {
  // Calea lui "u" sa inceapa mai jos decat cea a lui "v".
  if (d[begin[path[u]]] < d[begin[path[v]]]) {
    int tmp = u;
    u = v;
    v = tmp;
  }

  // Parcurge caile pentru a afla maximul.
  if (path[u] == path[v]) {
    int a, b;
    if (pos[u] < pos[v]) {
      a = pos[u];
      b = pos[v];
    } else {
      a = pos[v];
      b = pos[u];
    }
    return tree[path[u]].query(a, b);
  } else {
    return MAX(tree[path[u]].query(0, pos[u]), getAnswer(father[begin[path[u]]], v));
  }
}

int main(void) {
  int i, u, v, task;
  FILE *f = fopen("heavypath.in", "r");

  // Citirea datelor si construirea grafului.
  fscanf(f, "%d %d", &N, &M);
  for (i = 1; i <= N; i++) {
    fscanf(f, "%d", &val[i]);
  }
  for (i = 1; i < N; i++) {
    fscanf(f, "%d %d", &u, &v);
    addEdge(u, v, i);
    addEdge(v, u, i + N - 1);
  }

  // Construieste caile.
  heavyPath();
  makePaths();

  freopen("heavypath.out", "w", stdout);
  while (M) {
    fscanf(f, "%d %d %d", &task, &u, &v);
    if (task == 0) {
      tree[path[u]].update(pos[u], v);
    } else {
      fprintf(stdout, "%d\n", getAnswer(u, v));
    }
    M--;
  }
  fclose(f);
  fclose(stdout);
  return 0;
}