Cod sursa(job #2658938)

Utilizator MarcGrecMarc Grec MarcGrec Data 15 octombrie 2020 15:40:47
Problema Heavy Path Decomposition Scor 20
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 9.29 kb
#include <vector>
#include <utility>
#include <cstdlib>
#include <exception>

template<typename T, typename TFunc>
class IntervalTree
{
private:
	struct Node
	{
		size_t a, b;

		Node *parent, *left, *right;

		T val;
	};

public:
	IntervalTree(const std::vector<T>* _cont, TFunc _functor) :
		functor(std::move(_functor)),
		initialCont(_cont),
		root(nullptr),
		leaves(_cont->size(), nullptr)
	{
		ConstructTree(0, _cont->size() - 1, &root);

		initialCont = nullptr;
	}

	~IntervalTree()
	{
		DestructDownwards(&root);
	}

	void UpdateValue(size_t index, const T& val)
	{
		leaves[index]->val = val;

		UpdateUpwards(leaves[index]);
	}

	T GetRange(size_t a, size_t b) const
	{
		if (a > b)
		{
			size_t aux = a;
			a = b;
			b = aux;
		}
		
		return GetRange(leaves[a], a, b);
	}

private:
	void ConstructTree(const size_t a, const size_t b, Node** node)
	{
		if (a <= b)
		{
			(*node) = new Node;

			(*node)->parent = (*node)->right = (*node)->left = nullptr;

			(*node)->a = a;

			(*node)->b = b;

			if (a == b)
			{
				(*node)->val = initialCont->at(a);

				leaves[a] = (*node);
			}
			else
			{
				const size_t mean = (a + b) / 2;

				{
					Node* left;

					ConstructTree(a, mean, &left);
			
					(*node)->left = left;

					(*node)->left->parent = (*node);
				}

				{
					Node* right;

					ConstructTree(mean + 1, b, &right);

					(*node)->right = right;

					(*node)->right->parent = (*node);
				}

				UpdateNodeValue(*node);
			}
		}
		else
		{
			(*node) = nullptr;
		}
	}

	void DestructDownwards(Node** node)
	{
		if ((*node) != nullptr)
		{
			DestructDownwards(&((*node)->left));

			DestructDownwards(&((*node)->right));

			delete (*node);

			(*node) = nullptr;
		}
	}

	void UpdateNodeValue(Node* node)
	{
		if (node != nullptr)
		{
			if ((node->left != nullptr) && (node->right != nullptr))
			{
				node->val = functor(node->left->val, node->right->val);
			}
			else
			{
				if ((node->left != nullptr) && (node->right == nullptr))
				{
					node->val = node->left->val;
				}
				else
				{
					if ((node->left == nullptr) && (node->right != nullptr))
					{
						node->val = node->right->val;
					}
				}
			}
		}
	}

	void UpdateUpwards(Node* node)
	{
		if (node != nullptr)
		{
			UpdateNodeValue(node);
			UpdateUpwards(node->parent);
		}
	}

	T GetRange(Node* node, size_t a, size_t b) const
	{
		if (node->b < b)
		{
			T* ptrRightVal = nullptr;

			if (((node->parent->left == node) && (node->a != a)) || (node->a < a))
			{
				if (node->right->a >= a)
				{
					ptrRightVal = &(node->right->val);
				}
			}

			if (ptrRightVal != nullptr)
			{
				return functor(*ptrRightVal, GetRange(node->parent, a, b));
			}
			else
			{
				return GetRange(node->parent, a, b);
			}
		}
		else
		{
			if (node->b == b)
			{
				if (node->a >= a)
				{
					return node->val;
				}
				else
				{
					return GetRange(node->right, a, b);
				}
			}
			else
			{
				if (node->left->b >= b)
				{
					return GetRange(node->left, a, b);
				}
				else
				{
					if (node->left->a >= a)
					{
						return functor(node->left->val, GetRange(node->right, a, b));
					}
					else
					{
						return GetRange(node->right, a, b);
					}
				}
			}
		}
	}

private:
	TFunc functor;

private:
	const std::vector<T>* initialCont;

private:
	Node* root;

	std::vector<Node*> leaves;
};

#include <vector>
#include <exception>
#include <cstdint>

template<typename T, typename TFunc>
class RQ
{
private:
	static int IntLog2(uint64_t val)
	{
		int res = 0;

		while (val != 0)
		{
			val /= 2;
			++res;
		}

		return res - 1;
	}

public:
	RQ(const std::vector<T>& _cont, const TFunc& _functor) :
		functor(_functor),
		rangeVal((size_t) (IntLog2((uint64_t) _cont.size()) + 1ULL))
	{
		rangeVal[0] = std::vector<T>(_cont.size());

		for (size_t i = 0; i < _cont.size(); ++i)
		{
			rangeVal[0][i] = _cont[i];
		}

		for (size_t exp = 1; exp < rangeVal.size(); ++exp)
		{
			{
				size_t maI = 0;

				while ((maI + (1ULL << exp) - 1) < rangeVal[0].size())
				{
					++maI;
				}

				rangeVal[exp] = std::vector<T>(maI);
			}

			for (size_t i = 0; i < rangeVal[exp].size(); ++i)
			{
				rangeVal[exp][i] = functor(rangeVal[exp - 1][i], rangeVal[exp - 1][i + (1ULL << (exp - 1))]);
			}
		}
	}

	T GetRange(size_t a, size_t b) const
	{
		if (a > b)
		{
			size_t aux = a;
			a = b;
			b = aux;
		}
		
		const size_t elemCount = b - a + 1;

		const size_t exp = IntLog2(elemCount);

		return functor(rangeVal[exp][a], rangeVal[exp][b - (1ULL << exp) + 1]);
	}

private:
	TFunc functor;

	std::vector<std::vector<T>> rangeVal;
};

#define MAX_N 100000

#include <iostream>

#include <fstream>
#include <vector>
#include <queue>
#include <memory>
using namespace std;

ifstream fin("heavypath.in");
ofstream fout("heavypath.out");

int n, m, LVL[MAX_N + 1], T[MAX_N + 1];
vector<int> G[MAX_N + 1];

vector<int> Vals;

const auto fctorRq = [] (int node1, int node2) { return (LVL[node1] < LVL[node2]) ? node1 : node2; };
using RMQ = RQ<int, decltype(fctorRq)>;

const auto fctorIt = [] (int a, int b) { return (a > b) ? a : b; };
using IT = IntervalTree<int, decltype(fctorIt)>;

int P[MAX_N + 1];
RMQ* rmqLca;

struct Path
{
	shared_ptr<int> bottom = nullptr, top = nullptr;
	
	shared_ptr<vector<int>> temp = nullptr;
	
	shared_ptr<IT> it = nullptr;
};

Path Pth[MAX_N + 1];

void LevelGraph(int node);
void EulerTour(vector<int>& out);
int Lca(int node1, int node2);

void CreatePaths();

int GetNodePosition(int node);

int GetMax(int node1, int node2);

int main()
{
	fin >> n >> m;
	
	Vals = vector<int>(n + 1);
	for (int i = 1; i <= n; ++i)
	{
		fin >> Vals[i];
	}
	
	for (int i = 1; i < n; ++i)
	{
		int a, b;
		
		fin >> a >> b;
		
		G[a].push_back(b);
		G[b].push_back(a);
	}
	
	LevelGraph(1);
	
	{
		vector<int> eulerTour;
		
		EulerTour(eulerTour);
		
		rmqLca = new RMQ(eulerTour, fctorRq);
	}
	
	CreatePaths();
	
	Vals.clear();
	
	for (int i = 0; i < m; ++i)
	{
		int t;
		
		fin >> t;
		
		if (t == 0)
		{
			int x;
			int y;
			
			fin >> x >> y;
			
			int posX = GetNodePosition(x);
			
			Pth[x].it->UpdateValue(posX, y);
		}
		else
		{
			int x, y;
			
			fin >> x >> y;
			
			fout << GetMax(x, y) << '\n';
		}
	}
	
	delete rmqLca;
	rmqLca = nullptr;
	
	fin.close();
	fout.close();
	return 0;
}

void LevelGraph(int node)
{
	for (int i = 0; i < n; ++i)
	{
		T[i] = LVL[i] = 0;
	}
	
	queue<int> Q;
	Q.push(node);
	
	LVL[node] = 1;
	
	while (!Q.empty())
	{
		int front = Q.front();
		Q.pop();
		
		for (int adjNode : G[front])
		{
			if (LVL[adjNode] == 0)
			{
				T[adjNode] = front;
				
				LVL[adjNode] = LVL[front] + 1;
				
				Q.push(adjNode);
			}
		}
	}
}

int glP;

void EulerTour(int node, int fath, vector<int>& out)
{
	out[++glP] = node;
	P[node]    = glP;
	
	for (int adjNode : G[node])
	{
		if (adjNode != fath)
		{
			EulerTour(adjNode, node, out);
			
			out[++glP] = node;
		}
	}
}

void EulerTour(vector<int>& out)
{
	out = vector<int>(2 * n - 1);
	
	glP = -1;
	EulerTour(1, 0, out);
}

int Lca(int node1, int node2)
{
	return rmqLca->GetRange(P[node1], P[node2]);
}

void FinishPath(int node)
{
	vector<int> tempVals(Pth[node].temp->size());
	
	for (size_t i = 0; i < tempVals.size(); ++i)
	{
		tempVals[i] = Vals[Pth[node].temp->at(i)];
	}
	
	shared_ptr<IT> pIt(new IT(&tempVals, fctorIt));
	
	for (int nodeInPath : (*Pth[node].temp))
	{
		Pth[nodeInPath].it = pIt;
	}
	
	Pth[node].temp->clear();
}

int CreatePaths(int node, int fath)
{
	int resNode = 0;
	int ma = 0;
	int sum = 1;
	
	for (int adjNode : G[node])
	{
		if (adjNode != fath)
		{
			int res = CreatePaths(adjNode, node);
			
			sum += res;
			
			if (ma < res)
			{
				resNode = adjNode;
				ma = res;
			}
		}
	}
	
	if (resNode == 0)
	{
		Pth[node].bottom = shared_ptr<int>(new int(node));
		Pth[node].top = shared_ptr<int>(new int(node));
		
		Pth[node].temp = shared_ptr<vector<int>>(new vector<int>());
		
		Pth[node].temp->push_back(node);
	}
	else
	{
		Pth[node].bottom = Pth[resNode].bottom;
		Pth[node].top = Pth[resNode].top;
		Pth[node].temp = Pth[resNode].temp;
		
		(*Pth[node].top) = node;
		
		Pth[node].temp->push_back(node);
		
		for (int adjNode : G[node])
		{
			if ((adjNode != fath) && (adjNode != resNode))
			{
				FinishPath(adjNode);
			}
		}
	}
	
	return sum;
}

void CreatePaths()
{
	CreatePaths(1, 0);
	
	FinishPath(1);
}

int GetNodePosition(int node)
{
	return LVL[*Pth[node].bottom] - LVL[node];
}

int GetMaxUpwards(int node, int upperNode)
{
	if (Pth[node].it.get() != Pth[upperNode].it.get())
	{
		const int ma = Pth[node].it->GetRange(GetNodePosition(node), GetNodePosition(*Pth[node].top));
		
		return fctorIt(ma, GetMaxUpwards(T[node], upperNode));
	}
	else
	{
		return Pth[node].it->GetRange(GetNodePosition(node), GetNodePosition(upperNode));
	}
}

int GetMax(int node1, int node2)
{
	const int lca = Lca(node1, node2);
	
	const int ma1 = GetMaxUpwards(node1, lca);
	
	const int ma2 = GetMaxUpwards(node2, lca);
	
	return fctorIt(ma1, ma2);
}