Cod sursa(job #3259522)

Utilizator Traian_7109Traian Mihai Danciu Traian_7109 Data 26 noiembrie 2024 18:25:25
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.62 kb
#include <stdio.h>
#include <vector>

const int MAXN = 100'000;
const int AINTN = 1 << 17;
const int T_UPDATE = 0;
const int T_QUERY = 1;

FILE *fin, *fout;
std::vector<int> g[MAXN];
int n, q, v[MAXN];

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

int max(int a, int b) {
  return a > b ? a : b;
}

struct SegmentTree {
  int aint[AINTN << 1], n;

  void init(int n) {
    this->n = nextp2(n);
  }

  void update(int poz, int val) {
    aint[poz += n] = val;
    for(poz >>= 1; poz > 0; poz >>= 1) {
      aint[poz] = max(aint[2 * poz], aint[2 * poz + 1]);
    }
  }

  int query(int st, int dr) {
    int rez;

    st += n;
    dr += n;

    rez = 0;
    while(st <= dr) {
      if(st & 1) {
        rez = max(rez, aint[st++]);
      }
      st >>= 1;

      if(!(dr & 1)) {
        rez = max(rez, aint[dr--]);
      }
      dr >>= 1;
    }

    return rez;
  }
} aint;

struct HeavyLightDecomp {
  int poz[MAXN], path_start[MAXN], subtree_size[MAXN], current_poz;
  int heavy_fiu[MAXN], parent[MAXN], depth[MAXN];
  SegmentTree aint;

  void dfs(int nod) {
    int i, fiu, max_size;
    max_size = 0;
    heavy_fiu[nod] = -1;
    subtree_size[nod] = 1;
    for(i = 0; i < (int)g[nod].size(); i++) {
      fiu = g[nod][i];
      if(fiu != parent[nod]) {
        depth[fiu] = 1 + depth[nod];
        parent[fiu] = nod;
        dfs(fiu);
        subtree_size[nod] += subtree_size[fiu];
        if(subtree_size[fiu] > max_size) {
          max_size = subtree_size[fiu];
          heavy_fiu[nod] = fiu;
        }
      }
    }
  }

  void decomposeTree(int nod) {
    int i, fiu;
    if(heavy_fiu[nod] != -1) {
      poz[heavy_fiu[nod]] = current_poz++;
      path_start[heavy_fiu[nod]] = path_start[nod];
      decomposeTree(heavy_fiu[nod]);
    }
    for(i = 0; i < (int)g[nod].size(); i++) {
      fiu = g[nod][i];
      if(fiu != heavy_fiu[nod] && parent[nod] != fiu) {
        poz[fiu] = current_poz++;
        path_start[fiu] = fiu;
        decomposeTree(fiu);
      }
    }
  }

  void init() {
    int i;

    depth[0] = 0;
    parent[0] = -1;
    dfs(0);

    path_start[0] = poz[0] = 0;
    current_poz = 1;
    decomposeTree(0);

    aint.init(n);
    for(i = 0; i < n; i++) {
      aint.update(poz[i], v[i]);
    }
  }

  void update(int nod, int val) {
    aint.update(poz[nod], val);
  }

  int query(int u, int v) {
    int answer = 0;
    
    // Cat timp drumurile pana la radacina nu s-au intalnit
    while(path_start[u] != path_start[v]) {
      // Mai intai operam pe cel cu inceputul lantului mai jos
      if(depth[path_start[u]] > depth[path_start[v]]) {
        std::swap(u, v);
      }
      answer = max(answer, aint.query(poz[path_start[v]], poz[v]));
      v = parent[path_start[v]];
    }

    // Acum ei doi sunt pe acelasi lant deci cel de mai sus e LCA
    if(depth[u] > depth[v]) {
      std::swap(u, v);
    }
    answer = max(answer, aint.query(poz[u], poz[v]));

    return answer;
  }
} hld;

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

void readData() {
  int i, x, y;
  fscanf(fin, "%d%d", &n, &q);
  for(i = 0; i < n; i++) {
    fscanf(fin, "%d", &v[i]);
  }
  for(i = 1; i < n; i++) {
    fscanf(fin, "%d%d", &x, &y);
    g[--x].push_back(--y);
    g[y].push_back(x);
  }
}

void processOps() {
  int type, x, y;
  while(q--) {
    fscanf(fin, "%d%d%d", &type, &x, &y);
    x--;
    y--;
    if(type == T_UPDATE) {
      hld.update(x, y);
    } else { // T_QUERY
      fprintf(fout, "%d\n", hld.query(x, y));
    }
  }
}

void closeFiles() {
  fclose(fin);
  fclose(fout);  
}

int main() {
  openFiles();
  readData();
  hld.init();
  processOps();
  closeFiles();
  return 0;
}