Cod sursa(job #2655800)

Utilizator MarcGrecMarc Grec MarcGrec Data 5 octombrie 2020 16:33:33
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.67 kb
#define MAX_N 100000
#define MAX_N_LOG 16

#include <iostream>

#include <fstream>
#include <vector>
#include <algorithm>
#include <memory>
#include <utility>
using namespace std;

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

struct ITNode
{
	ITNode(int _a, int _b, ITNode* _parent) : a(_a), b(_b), parent(_parent), left(nullptr), right(nullptr)
	{
	}
	
	int a, b, ma;
	ITNode *parent, *left, *right;
};

// Interval tree
struct IT
{
	IT(vector<int>&& _inter) : inter(move(_inter)), leaves(inter.size())
	{
		ConstructIT(0, inter.size() - 1, root = new ITNode(0, inter.size() - 1, nullptr));
	}
	
	~IT()
	{
		Cleanup(root);
	}
	
	void ChangeVal(int index, int val)
	{
		--index;
		
		inter[index] = val;
		leaves[index]->ma = val;
		
		Update(leaves[index]->parent);
	}
	
	int GetMax(int a, int b)
	{
		{
			--a;
			--b;
		}
		
		if (a > b)
		{
			swap(a, b);
		}
		
		return GetRange(leaves[a], a, b);
	}
	
	int GetRange(ITNode* node, int a, int b)
	{	
		if (node->b < b)
		{
			int ma = 0;
			
			if (node->right != nullptr)
			{
				if ((a <= node->right->a) && (b >= node->right->b))
				{
					ma = node->right->ma;
				}
			}
			
			return max(ma, GetRange(node->parent, a, b));
		}
		else
		{
			if (node->b == b)
			{
				if (node->a >= a)
				{
					return node->ma;
				}
				else
				{
					return GetRange(node->right, a, b);
				}
			}
			
			if (node->left->b < b)
			{
				int lma = 0;
				
				if (node->left->a >= a)
				{
					lma = node->left->ma;
				}
				
				return max(lma, GetRange(node->right, a, b));
			}
			else
			{
				return GetRange(node->left, a, b);
			}
		}
	}
	
	void Update(ITNode* node)
	{
		if (node != nullptr)
		{
			int lma = 0, rma = 0;
			
			if (node->left != nullptr)
			{
				lma = node->left->ma;
			}
			
			if (node->right != nullptr)
			{
				rma = node->right->ma;
			}
			
			node->ma = max(lma, rma);
			
			Update(node->parent);
		}
	}
	
	void Cleanup(ITNode*& node)
	{
		if (node != nullptr)
		{
			Cleanup(node->left);
			Cleanup(node->right);
			
			delete node;
			node = nullptr;
		}
	}
	
	void ConstructIT(int a, int b, ITNode* node)
	{
		node->a = a;
		node->b = b;
		
		if (a == b)
		{
			node->ma  = inter[a];
			leaves[a] = node;
		}
		else
		{
			const int mid = (a + b) / 2;
			
			node->left = new ITNode(a, mid, node);
			node->right = new ITNode(mid + 1, b, node);
			
			ConstructIT(a, mid, node->left);
			ConstructIT(mid + 1, b, node->right);
			
			node->ma = max(node->left->ma, node->right->ma);
		}
	}
	
	ITNode* root = nullptr;
	
	vector<int> inter;
	vector<ITNode*> leaves;
};

struct A
{
	~A()
	{
		if (tree != nullptr)
		{
			delete tree;
			tree = nullptr;
		}
	}
	
	IT* tree = nullptr;
	int bottom, top;
};

int n, m;
int T[MAX_N + 1], V[MAX_N + 1], LVL[MAX_N + 1];
shared_ptr<A> Piece[MAX_N + 1];

shared_ptr<vector<int>> Paths[MAX_N + 1];

vector<int> G[MAX_N + 1];

int glEInd = 0;
int E[2 * MAX_N], P[MAX_N + 1], RMQ[MAX_N_LOG + 2][2 * MAX_N];

void ReadData();

void Init();

void EulerTour(int node);

void DoRmq();

int LCA(int x, int y);

int PathDecomposition(int node);

int MaxValueOnRoad(int x, int y);

void ChangeNodeValue(int node, int value);

int main()
{
	ReadData();
	
	Init();
	
	for (int i = 1; i <= m; ++i)
	{
		int t, x, y;
		
		fin >> t >> x >> y;
		
		if (t == 0)
		{
			ChangeNodeValue(x, y);
		}
		else
		{
			fout << MaxValueOnRoad(x, y) << '\n';
		}
	}
	
	fin.close();
	fout.close();
	return 0;
}

void Dfs(int node)
{
	for (int adjNode : G[node])
	{
		if (T[node] != adjNode)
		{
			T[adjNode] = node;
			
			Dfs(adjNode);
		}
	}
}

void ReadData()
{
	fin >> n >> m;
	
	for (int i = 1; i <= n; ++i)
	{
		fin >> V[i];
	}
	
	for (int i = 1; i < n; ++i)
	{
		int x, y;
		fin >> x >> y;
		
		G[x].push_back(y);
		G[y].push_back(x);
	}
}

void Init()
{
	for (int i = 1; i <= n; ++i)
	{
		T[i] = 0;
	}
	
	Dfs(1);
	
	LVL[1] = 1;
	EulerTour(1);
	
	DoRmq();
	
	PathDecomposition(1);
	
	for (int i = 1; i <= n; ++i)
	{
		if (Piece[i].get() == nullptr)
		{
			Piece[i] = shared_ptr<A>(new A);
			
			for (int node : (*Paths[i]))
			{	
				Piece[node] = Piece[i];
			}
			
			Piece[i]->bottom = (*Paths[i]).front();
			Piece[i]->top    = (*Paths[i]).back();
			
			vector<int> values;
			for (int node : (*Paths[i]))
			{
				values.push_back(V[node]);
			}
			
			Piece[i]->tree = new IT(move(values));
		}
	}
}

void EulerTour(int node)
{
	E[++glEInd] = node;
	P[node]     = glEInd;
	
	for (int adjNode : G[node])
	{
		if (T[adjNode] == node)
		{
			LVL[adjNode] = LVL[node] + 1;
			
			EulerTour(adjNode);
			
			E[++glEInd] = node;
		}
	}
}

void DoRmq()
{	
	for (int i = 1; i < (2 * n); ++i)
	{
		RMQ[0][i] = LVL[E[i]];
	}
	
	for (int exp = 1; (1 << exp) < (2 * n); ++exp)
	{
		for (int i = 1; (i + (1 << (exp - 1))) < (2 * n); ++i)
		{
			RMQ[exp][i] = min(RMQ[exp - 1][i], RMQ[exp - 1][i + (1 << (exp - 1))]);
		}
	}
}

int LCA(int x, int y)
{
	x = P[x];
	y = P[y];
	
	if (x > y)
	{
		swap(x, y);
	}
	
	const int l = y - x + 1;
	
	int logL = -1;
	{
		int auxL = l;
		while (auxL != 0)
		{	
			auxL /= 2;
			++logL;
		}
	}
	
	return min(RMQ[logL][x], RMQ[logL][y - (1 << logL) + 1]);
}

int PathDecomposition(int node)
{
	int res = 1;
	int resAdjMax = 0;
	int adjNodeMax = -1;
	
	for (int adjNode : G[node])
	{
		if (T[adjNode] == node)
		{
			int resAdj = PathDecomposition(adjNode);
			
			if (resAdjMax < resAdj)
			{
				resAdjMax = resAdj;
				adjNodeMax = adjNode;
			}
			
			res += resAdj;
		}
	}
	
	if (adjNodeMax == -1)
	{
		Paths[node] = shared_ptr<vector<int>>(new vector<int>());
	}
	else
	{
		Paths[node] = Paths[adjNodeMax];
	}
	
	Paths[node]->push_back(node);
	
	return res;
}

int GetMaxValueOnParentRoad(int x, int y)
{
	if (Piece[x].get() == Piece[y].get())
	{
		int posX = LVL[Piece[x]->bottom] - LVL[x] + 1;
		int posY = LVL[Piece[x]->bottom] - LVL[y] + 1;
		
		return Piece[x]->tree->GetMax(posX, posY);
	}
	else
	{
		return max(Piece[x]->tree->GetMax(LVL[Piece[x]->bottom] - LVL[x] + 1, LVL[Piece[x]->bottom] - LVL[Piece[x]->top] + 1), GetMaxValueOnParentRoad(T[Piece[x]->top], y));
	}
}

int MaxValueOnRoad(int x, int y)
{
	int lca = LCA(x, y);
	
	int res1 = GetMaxValueOnParentRoad(x, lca);
	
	int res2 = GetMaxValueOnParentRoad(y, lca);
	
	return max(res1, res2);
}

void ChangeNodeValue(int node, int value)
{
	int nodeInd = LVL[Piece[node]->bottom] - LVL[node] + 1;
	
	V[node] = value;
	Piece[node]->tree->ChangeVal(nodeInd, value);
}