Cod sursa(job #3350953)

Utilizator DobraVictorDobra Victor Ioan DobraVictor Data 15 aprilie 2026 10:28:18
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.27 kb
#include <iostream>
#include <fstream>
#include <stdint.h>

const int32_t MAX_N = 100000;
const int32_t MAX_M = 100000;
const int32_t MAX_TREE = 1 << 18;

int32_t max(int32_t x, int32_t y) {
	return (x > y) ? x : y;
}
int32_t LowestPow2(int32_t val) {
	int32_t res = val - 1;
	res |= res >> 1;
	res |= res >> 2;
	res |= res >> 4;
	res |= res >> 8;
	res |= res >> 16;
	return res + 1;
}

struct SegTree {
	int32_t n;
	int32_t vals[MAX_TREE];

	void Init(int32_t n) {
		this->n = LowestPow2(n);
	}
	void AssignVal(int32_t ind, int32_t val) {
		vals[ind + n] = val;
	}
	void Build() {
		for(int32_t i = n - 1; i; --i)
			vals[i] = max(vals[i << 1], vals[(i << 1) + 1]);
	}

	void SetVal(int32_t ind, int32_t val) {
		ind += n;
		vals[ind] = val;
		for(ind >>= 1; ind; ind >>= 1)
			vals[ind] = max(vals[ind << 1], vals[(ind << 1) + 1]);
	}
	int32_t GetMax(int32_t left, int32_t right) {
		left += n;
		right += n;

		int32_t res = 0;
		while(left <= right) {
			if(left & 1)
				res = max(res, vals[left++]);
			left >>= 1;

			if(!(right & 1))
				res = max(res, vals[right--]);
			right >>= 1;
		}

		return res;
	}
};

struct Node {
	int32_t val;
	int32_t adjStart, parent;
	int32_t depth, timeIn;
	int32_t heavy, head;
};
struct AdjItem {
	int32_t node;
	int32_t next;
};

int32_t n, m;
Node nodes[MAX_N];
AdjItem adj[(MAX_N - 1) << 1];
SegTree maxTree;

int32_t GetPathMax(int32_t node1, int32_t node2) {
	int32_t res = 0;
	while(nodes[node1].head != nodes[node2].head) {
		if(nodes[nodes[node1].head].depth > nodes[nodes[node2].head].depth)
			std::swap(node1, node2);
		
		int32_t head = nodes[node2].head;
		res = max(res, maxTree.GetMax(nodes[head].timeIn, nodes[node2].timeIn));
		node2 = nodes[head].parent;
	}

	if(nodes[node1].timeIn > nodes[node2].timeIn)
		std::swap(node1, node2);
	res = max(res, maxTree.GetMax(nodes[node1].timeIn, nodes[node2].timeIn));

	return res;
}

void ReadData(std::istream& fin) {
	fin >> n >> m;

	for(int32_t i = 0; i != n; ++i) {
		fin >> nodes[i].val;
		nodes[i].adjStart = -1;
	}
	for(int32_t i = 0; i != n - 1; ++i) {
		int32_t node1, node2;
		fin >> node1 >> node2;
		--node1; --node2;

		adj[i << 1].node = node2;
		adj[i << 1].next = nodes[node1].adjStart;
		nodes[node1].adjStart = i << 1;

		adj[(i << 1) + 1].node = node1;
		adj[(i << 1) + 1].next = nodes[node2].adjStart;
		nodes[node2].adjStart = (i << 1) + 1;
	}

	nodes[0].parent = -1;
	nodes[0].depth = 0;
	nodes[0].head = 0;
}
int32_t DFSFindHeavy(int32_t node) {
	int32_t size = 1;
	int32_t heavy = -1, heavySize = 0;

	for(int32_t ind = nodes[node].adjStart; ind != -1; ind = adj[ind].next) {
		int32_t next = adj[ind].node;
		if(next == nodes[node].parent)
			continue;
		
		nodes[next].parent = node;
		nodes[next].depth = nodes[node].depth + 1;
		int32_t childSize = DFSFindHeavy(next);

		size += childSize;
		if(childSize > heavySize) {
			heavy = next;
			heavySize = childSize;
		}
	}

	nodes[node].heavy = heavy;
	return size;
}
void DFSLinearize(int32_t node) {
	static int32_t globalTime = 0;

	nodes[node].timeIn = globalTime++;
	if(nodes[node].heavy == -1)
		return;

	nodes[nodes[node].heavy].head = nodes[node].head;
	DFSLinearize(nodes[node].heavy);

	for(int32_t ind = nodes[node].adjStart; ind != -1; ind = adj[ind].next) {
		int32_t next = adj[ind].node;
		if(next == nodes[node].parent || next == nodes[node].heavy)
			continue;
		
		nodes[next].head = next;
		DFSLinearize(next);
	}
}
void InitMaxTree() {
	maxTree.Init(n);
	for(int32_t i = 0; i != n; ++i)
		maxTree.AssignVal(nodes[i].timeIn, nodes[i].val);
	maxTree.Build();
}
void SolveQueries(std::istream& fin, std::ostream& fout) {
	while(m--) {
		int32_t t;
		fin >> t;

		if(t == 0) {
			int32_t node, val;
			fin >> node >> val;
			--node;

			nodes[node].val = val;
			maxTree.SetVal(nodes[node].timeIn, val);
		} else {
			int32_t node1, node2;
			fin >> node1 >> node2;
			--node1; --node2;

			fout << GetPathMax(node1, node2) << '\n';
		}
	}
}

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

	ReadData(fin);
	DFSFindHeavy(0);
	DFSLinearize(0);
	InitMaxTree();
	SolveQueries(fin, fout);

	fin.close();
	fout.close();

	return 0;
}