Cod sursa(job #3140350)

Utilizator cezar_titianuTitianu Cezar cezar_titianu Data 5 iulie 2023 17:11:59
Problema Heavy Path Decomposition Scor 60
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.9 kb
#include <fstream>
#include <vector>
#include <iostream>

#define MAXN 100005

class FenwickTree {
private:
	int size;
	int vec[3 * MAXN];

	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;
	}
	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 Tree {
public:
	struct Node {
		int par[17];
		std::vector <int> chd;

		int sub_size = 0;
		int depth = 0;
	};

private:
	Node vec[MAXN];

	void InitDFS (int node, int par) {
		if (par == -1) {
			vec[node].depth = 0;
		}
		else {
			vec[node].depth = vec[par].depth + 1;
			vec[node].par[0] = par;
			for (int i = 1; 1 << i <= vec[node].depth; i++) {
				vec[node].par[i] = vec[vec[node].par[i - 1]].par[i - 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:
	int size;

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

	void InitTree() {
		InitDFS(0, -1);
	}

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

	int GetPar (int node, int target) const {
		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) const {
		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 (1 << bit < vec[node1].depth && vec[node1].par[bit] != vec[node2].par[bit]) {
				node1 = vec[node1].par[bit];
				node2 = vec[node2].par[bit];
			}
		}
		return vec[node1].par[0];
	}
};

Tree tree;
int vals[MAXN];

class HeavyPath {
private:
	int size;
	FenwickTree aint;

	int aint_cnt = 0;
	int aint_pos[MAXN];
	int chain_top[MAXN];

	void ChainDFS (int node, int top) {
		chain_top[node] = top;
		Tree::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 () : aint(tree.size) {
		size = tree.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;
	int val1, val2;
	int task;

	fin >> n >> m;
	tree.size = n;
	for (i = 0; i < n; i++) {
		fin >> vals[i];
	}
	for (i = 0; i < n - 1; i++) {
		fin >> val1 >> val2;
		tree.AddEdge(--val1, --val2);
	}
	tree.InitTree();
	HeavyPath solve;
	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;
}