Cod sursa(job #2241769)

Utilizator LucaSeriSeritan Luca LucaSeri Data 16 septembrie 2018 22:14:39
Problema Heavy Path Decomposition Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 5.9 kb
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <ctype.h>
#include <cstring>
using namespace std;

const int MAXN = 1e5;
const int MAXM = 1e5;
const int MAXVAL = 2e9;
class InParser {
private:
    FILE *fin;
    char *buff;
    int sp;

    char read_ch() {
        ++sp;
        if (sp == 4096) {
            sp = 0;
            fread(buff, 1, 4096, fin);
        }
        return buff[sp];
    }

public:
    InParser(const char* nume) {
        fin = fopen(nume, "r");
        buff = new char[4096]();
        sp = 4095;
    }

    InParser& operator >> (int &n) {
        char c;
        while (!isdigit(c = read_ch()) && c != '-');
        int sgn = 1;
        if (c == '-') {
            n = 0;
            sgn = -1;
        } else {
            n = c - '0';
        }
        while (isdigit(c = read_ch())) {
            n = 10 * n + c - '0';
        }
        n *= sgn;
        return *this;
    }

    InParser& operator >> (long long &n) {
        char c;
        n = 0;
        while (!isdigit(c = read_ch()) && c != '-');
        long long sgn = 1;
        if (c == '-') {
            n = 0;
            sgn = -1;
        } else {
            n = c - '0';
        }
        while (isdigit(c = read_ch())) {
            n = 10 * n + c - '0';
        }
        n *= sgn;
        return *this;
    }
};

class OutParser {
private:
    FILE *fout;
    char *buff;
    int sp;

    void write_ch(char ch) {
        if (sp == 50000) {
            fwrite(buff, 1, 50000, fout);
            sp = 0;
            buff[sp++] = ch;
        } else {
            buff[sp++] = ch;
        }
    }


public:
    OutParser(const char* name) {
        fout = fopen(name, "w");
        buff = new char[50000]();
        sp = 0;
    }
    ~OutParser() {
        fwrite(buff, 1, sp, fout);
        fclose(fout);
    }

    OutParser& operator << (int vu32) {
        if (vu32 <= 9) {
            write_ch(vu32 + '0');
        } else {
            (*this) << (vu32 / 10);
            write_ch(vu32 % 10 + '0');
        }
        return *this;
    }

    OutParser& operator << (long long vu64) {
        if (vu64 <= 9) {
            write_ch(vu64 + '0');
        } else {
            (*this) << (vu64 / 10);
            write_ch(vu64 % 10 + '0');
        }
        return *this;
    }

    OutParser& operator << (char ch) {
        write_ch(ch);
        return *this;
    }
    OutParser& operator << (const char *ch) {
        while (*ch) {
            write_ch(*ch);
            ++ch;
        }
        return *this;
    }
};
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(MAXN + 1);

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

  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());
    int nn = 1;
    while(nn < P.size()) nn <<= 1;
    nn <<= 1;
    T.resize(nn );
    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);
    }
  }

};

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) {
  int ans = -1;
  while (nodes[a].pat != nodes[b].pat) {
    if (nodes[paths[nodes[a].pat].par].niv < nodes[paths[nodes[b].pat].par].niv)
        swap(a, b);

        ans = max(paths[nodes[a].pat].query(1, 1, paths[nodes[a].pat].P.size(), 1, nodes[a].pos), ans);
        a = paths[nodes[a].pat].par;
  }

  return max(ans, paths[nodes[a].pat].query(1, 1, paths[nodes[a].pat].P.size(), min(nodes[a].pos, nodes[b].pos), max(nodes[a].pos, nodes[b].pos)));
}

int main() {

   InParser f("heavypath.in");
   OutParser h("heavypath.out");
   f >> n >> m;

  for (int i = 1; i <= n; ++ i) f >> nodes[i].val;

  for (int i = 1; i < n; ++ i) {
    int a, b;
    f >> 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) {
    f >> t >> a >> b;
    if (t)
    h << solve1(a, b) << '\n';
    else
      solve0(a, b);
  }
  return 0;
}