Cod sursa(job #3140278)

Utilizator cezar_titianuTitianu Cezar cezar_titianu Data 5 iulie 2023 11:30:48
Problema Heavy Path Decomposition Scor 20
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.61 kb
#include <fstream>
#include <vector>

class FenwickTree {
private:
	int size;
	std::vector<int> vec;

	void ReplacePirv(int nod, int st, int dr, int pos, int val) {
		if (st == dr)
			vec[nod] = val;
		else {
			int mij = (st + dr) / 2;
			if (pos <= mij)
				ReplacePirv(2 * nod + 1, st, mij, pos, val);
			else
				ReplacePirv(2 * nod + 2, mij + 1, dr, pos, val);
			vec[nod] = std::max(vec[2 * nod + 1], vec[2 * nod + 2]);
		}
	}
	int MaximumPriv(int nod, int st, int dr, int pos1, int pos2) {
		if (st == pos1 && dr == pos2)
			return vec[nod];
		else {
			int mij = (st + dr) / 2;
			int ans = -1;
			if (pos1 <= mij)
				ans = MaximumPriv(2 * nod + 1, st, mij, pos1, std::min(pos2, mij));
			if (mij + 1 <= pos2)
				ans = std::max(ans, MaximumPriv(2 * nod + 2, mij + 1, dr,
				                                std::max(pos1, mij + 1), pos2));
			return ans;
		}
	}

public:
	FenwickTree(int set_size) {
		size = set_size;
		vec.resize(4 * size);
	}
	void Replace(int pos, int val) { ReplacePirv(0, 0, size - 1, pos, val); }
	int Maximum(int pos1, int pos2) {
		return MaximumPriv(0, 0, size - 1, pos1, pos2);
	}
};

class FormTree {
public:
	struct MiniNode {
		std::vector<int> chd;
	};

private:
	int size;
	std::vector<MiniNode> vec;

public:
	FormTree(int set_size) {
		size = set_size;
		vec.resize(size);
	}

	void AddEdge(int node1, int node2) {
		vec[node1].chd.push_back(node2);
		vec[node2].chd.push_back(node1);
	}

	int GetSize() const {
		return size;
	}
	const std::vector <MiniNode> &GetGraph() const {
		return vec;
	}
};

class SolidTree {
public:
	struct Node {
		std::vector<int> par;
		std::vector<int> chd;

		int sub_size;
		int depth;
	};

private:
	int size;
	std::vector<Node> vec;

	void InitDFS(int node, int par) {
		if (par == -1) {
			vec[node].depth = 0;
		} else {
			vec[node].depth = vec[par].depth + 1;
			vec[node].par.push_back(par);
			while (vec[vec[node].par.back()].par.size() >= vec[node].par.size()) {
				vec[node].par.push_back(vec[vec[node].par.back()].par[vec[node].par.size() - 1]);
			}
		}

		vec[node].sub_size = 1;
		for (int i = 0; i < vec[node].chd.size(); i++) {
			if (vec[node].chd[i] == par) {
				std::swap(vec[node].chd[i], vec[node].chd.back());
				vec[node].chd.pop_back();
				i--;
				continue;
			}
			InitDFS(vec[node].chd[i], node);
			vec[node].sub_size += vec[vec[node].chd[i]].sub_size;
		}
	}

public:
	SolidTree(const FormTree &solidify) {
		size = solidify.GetSize();
		const std::vector <FormTree::MiniNode> &temp_vec = solidify.GetGraph();
		vec.resize(size);
		for (int i = 0; i < size; i++) {
			vec[i].chd = temp_vec[i].chd;
		}
		InitDFS(0, -1);
	}

	Node GetNode(int node) { return vec[node]; }

	int GetPar(int node, int target) {
		if (vec[node].depth > target) {
			int log_size = 31 - __builtin_clz(vec[node].depth - target);
			for (int bit = log_size; bit >= 0; bit--) {
				if (vec[node].depth - target >= 1 << bit) {
					node = vec[node].par[bit];
				}
			}
		}
		return node;
	}
	int GetLCA(int node1, int node2) {
		if (vec[node1].depth < vec[node2].depth) {
			std::swap(node1, node2);
		}
		node1 = GetPar(node1, vec[node2].depth);
		if (node1 == node2) {
			return node1;
		}
		int log_size = 31 - __builtin_clz(vec[node1].depth);
		for (int bit = log_size; bit >= 0; bit--) {
			if (vec[node1].par[bit] != vec[node2].par[bit]) {
				node1 = vec[node1].par[bit];
				node2 = vec[node2].par[bit];
			}
		}
		return vec[node1].par[0];
	}
};

class HeavyPath {
private:
	int size;
	FenwickTree aint;
	SolidTree tree;

	std::vector<int> vals;
	int aint_cnt = 0;
	std::vector<int> aint_pos;
	std::vector<int> chain_top;

	void ChainDFS(int node, int top) {
		chain_top[node] = top;
		SolidTree::Node myNode = tree.GetNode(node);
		int max_chd = -1;
		int max_size = -1;
		int now_size;
		for (int chd : myNode.chd) {
			now_size = tree.GetNode(chd).sub_size;
			if (now_size > max_size) {
				max_chd = chd;
				max_size = now_size;
			}
		}
		aint_pos[node] = aint_cnt++;
		aint.Replace(aint_pos[node], vals[node]);
		if (max_chd != -1) {
			ChainDFS(max_chd, top);
			for (int chd : myNode.chd) {
				if (max_chd == chd) {
					continue;
				}
				ChainDFS(chd, chd);
			}
		}
	}

	int MaxClimb(int node, int min_depth) {
		if (tree.GetNode(node).depth < min_depth) {
			return -1;
		}
		int top = chain_top[node];
		if (tree.GetNode(top).depth <= min_depth) {
			top = tree.GetPar(node, min_depth);
			return aint.Maximum(aint_pos[top], aint_pos[node]);
		}
		else {
			int par_top = tree.GetNode(top).par[0];
			return std::max(aint.Maximum(aint_pos[top], aint_pos[node]),
			                MaxClimb(par_top, min_depth));
		}
	}

public:
	HeavyPath(const FormTree &tree_state, std::vector <int> &&get_vals) : aint(tree_state.GetSize()), tree(tree_state) {
		size = tree_state.GetSize();
		vals = get_vals;
		aint_pos.resize(size);
		chain_top.resize(size);
		ChainDFS(0, 0);
	}

	void Update(int node, int val) { aint.Replace(aint_pos[node], val); }
	int Maximum(int node1, int node2) {
		int lca = tree.GetLCA(node1, node2);
		int lca_depth = tree.GetNode(lca).depth;
		return std::max(MaxClimb(node1, lca_depth), MaxClimb(node2, lca_depth + 1));
	}
};

int main() {
	std::ifstream fin("heavypath.in");
	std::ofstream fout("heavypath.out");

	int n, m;
	int i, val;
	int val1, val2;
	int task;

	fin >> n >> m;
	FormTree temp_tree(n);
	std::vector <int> vals(n);
	for (i = 0; i < n; i++) {
		fin >> vals[i];
	}
	for (i = 0; i < n - 1; i++) {
		fin >> val1 >> val2;
		temp_tree.AddEdge(--val1, --val2);
	}

	HeavyPath solve(temp_tree, std::move(vals));
	for (i = 0; i < m; i++) {
		fin >> task >> val1 >> val2;
		if (task == 0) {
			solve.Update(--val1, val2);
		}
		else {
			fout << solve.Maximum(--val1, --val2) << '\n';
		}
	}
	return 0;
}