Cod sursa(job #1847257)

Utilizator BrandonChris Luntraru Brandon Data 14 ianuarie 2017 14:05:08
Problema Heavy Path Decomposition Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 4.58 kb
#include <cstring>
#include <fstream>
#include <vector>
#include <cmath>

using namespace std;

class InputReader {
public:
  InputReader() {}
  InputReader(const char *file_name) {
    input_file = fopen(file_name, "r");
    cursor = 0;
    fread(buffer, SIZE, 1, input_file);
  }
  inline InputReader &operator >>(int &n) {
    while (buffer[cursor] < '0' || buffer[cursor] > '9') {
      advance();
    }
    n = 0;
    while ('0' <= buffer[cursor] && buffer[cursor] <= '9') {
      n = n * 10 + buffer[cursor] - '0';
      advance();
    }
    return *this;
  }
private:
  FILE *input_file;
  static const int SIZE = 1 << 17;
  int cursor;
  char buffer[SIZE];
  inline void advance() {
    ++ cursor;
    if (cursor == SIZE) {
      cursor = 0;
      fread(buffer, SIZE, 1, input_file);
    }
  }
};

InputReader cin ("heavypath.in");
ofstream cout ("heavypath.out");

const int MaxN = 100005, TreeSize = (1 << 19);

vector <int> G[MaxN];
int n, m, treeTop;
int v[MaxN], depth[MaxN], son[MaxN], Tree[TreeSize], treePos[MaxN], father[MaxN];
bool used[MaxN];

class Path {
public:
	int pathSt, depth, lf, rg;

	Path(int _pathSt = 0, int _depth = 1, int _lf = 0, int _rg = 0) {
		pathSt = _pathSt;
		depth = _depth;
		lf = _lf;
		rg = _rg;
	}

	inline bool operator >= (const Path &other) const {
		return depth >= other.depth;
	}
};

Path nullPath = Path();
Path* pathOf[MaxN];
vector <Path*> pathList;

void Dfs(int node = 1, int level = 1) {
	used[node] = true;
	depth[node] = level;
	if (G[node].size() == 1 and node != 1) {
		pathOf[node] = new Path;
		pathOf[node]->pathSt = node;
		pathList.push_back(pathOf[node]);
		return;
	}

	Path *bestPath = &nullPath;
	for (auto nxt: G[node]) {
		if (used[nxt]) {
			continue;
		}

		father[nxt] = node;
		Dfs(nxt, level + 1);
		if (*pathOf[nxt] >= *bestPath) {
			bestPath = pathOf[nxt];
		}
	}

	son[node] = bestPath->pathSt;
	pathOf[node] = bestPath;
	++pathOf[node]->depth;
	pathOf[node]->pathSt = node;
}

inline void BuildNode(int &node, int &lf, int &rg) {
	node = max(lf, rg);
}

void Update(int CurrTree[], int pos, int val, int lf, int rg, int node = 1) {
	if (lf == rg) {
		CurrTree[node] = val;
		return;
	}

	int lfSon = 2 * node;
	int rgSon = 2 * node + 1;
	int med = (lf + rg) / 2;

	if (pos <= med) {
		Update(CurrTree, pos, val, lf, med, lfSon);
	}
	else {
		Update(CurrTree, pos, val, med + 1, rg, rgSon);
	}

	BuildNode(CurrTree[node], CurrTree[lfSon], CurrTree[rgSon]);
}

void Query(int &ans, int CurrTree[], int srLf, int srRg, int lf, int rg, int node = 1) {
	if (srLf <= lf and srRg >= rg) {
		ans = max(ans, CurrTree[node]);
		return;
	}

	if (lf > srRg or rg < srLf) {
		return;
	}

	int lfSon = 2 * node;
	int rgSon = 2 * node + 1;
	int med = (lf + rg) / 2;

	Query(ans, CurrTree, srLf, srRg, lf, med, lfSon);
	Query(ans, CurrTree, srLf, srRg, med + 1, rg, rgSon);
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; ++i) {
		cin >> v[i];
	}

	for (int i = 1; i <= n - 1; ++i) {
		int a, b;
		cin >> a >> b;
		G[a].push_back(b);
		G[b].push_back(a);
	}

	memset(son, -1, sizeof son);
	Dfs();

	for (auto &it: pathList) {
		int node = it->pathSt;
		while (node != -1) {
			treePos[node] = depth[node] - depth[it->pathSt] + 1;
			node = son[node];
		}

		it->lf = treeTop + 1;
		it->rg = log2(it->depth);
		it->rg += (1 << it->rg) < it->depth;
		it->rg = 1 << (it->rg);
		treeTop += it->rg * 2;
	}

	// for (int i = 1; i <= n; ++i) {
 //    cout << pathOf[i]->pathSt << '\n';
	// }
	// cout << '\n';

	for (int i = 1; i <= n; ++i) {
    Update(Tree + pathOf[i]->lf, treePos[i], v[i], 1, pathOf[i]->rg);
	}

	for (int i = 1; i <= m; ++i) {
		int type, a, b;
		cin >> type >> a >> b;
		//Update
		if (type == 0) {
			int currLf = pathOf[a]->lf;
			int currRg = pathOf[a]->rg;
			Update(Tree + currLf, treePos[a], b, 1, currRg);
		}
		//Query
		else {
			auto ita = pathOf[a];
			auto itb = pathOf[b];
			int ans = 0;
			while (ita != itb) {
				if (depth[ita->pathSt] > depth[itb->pathSt]) {
					Query(ans, Tree + ita->lf, 1, depth[a] - depth[ita->pathSt] + 1, 1, ita->rg);
					a = father[ita->pathSt];
					ita = pathOf[a];
				}
				else {
					Query(ans, Tree + itb->lf, 1, depth[b] - depth[itb->pathSt] + 1, 1, itb->rg);
					b = father[itb->pathSt];
					itb = pathOf[b];
				}
			}

			if (depth[a] > depth[b]) {
				swap(a, b);
			}

			Query(ans, Tree + ita->lf, depth[a] - depth[ita->pathSt] + 1, depth[b] - depth[itb->pathSt] + 1, 1, ita->rg);
			cout << ans <<'\n';
		}
	}
	return 0;
}