Cod sursa(job #992887)

Utilizator alex_unixPetenchea Alexandru alex_unix Data 2 septembrie 2013 18:31:18
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 4.26 kb

#include <cstdio>
#include <vector>
#include <algorithm>

const int MAX_N(100005);

int n, m, Chains;
std::vector<int> Graph [MAX_N];
int Value [MAX_N];
std::vector<int> Chain [MAX_N];
int ChainIndex [MAX_N];
int ChainParent [MAX_N];
int Position [MAX_N];
int ItIndex [MAX_N];
int It [MAX_N << 2];
int Level [MAX_N];
int Weight [MAX_N];

inline void Read (void)
{
	std::scanf("%d %d",&n,&m);
	int i;
	for (i = 1 ; i <= n ; ++i)
		std::scanf("%d",&Value[i]);
	int a, b;
	for (i = 1 ; i < n ; ++i)
	{
		std::scanf("%d %d",&a,&b);
		Graph[a].push_back(b);
		Graph[b].push_back(a);
	}
}

void DepthFirstSearch (int parent, int node, int level)
{
	Level[node] = level;
	if (Graph[node].size() == 1 && node != 1)
	{
		++Chains;
		ChainIndex[node] = Chains;
		Chain[Chains].push_back(node);
		ChainParent[Chains] = parent;
		Weight[node] = 1;
		return;
	}
	int optimal(0), weight(0);
	for (auto it : Graph[node])
		if (it != parent)
		{
			DepthFirstSearch(node,it,level + 1);
			if (weight < Weight[it])
			{
				optimal = ChainIndex[it];
				weight = Weight[it];
			}
			Weight[node] += Weight[it];
		}
	++Weight[node];
	Chain[optimal].push_back(node);
	ChainIndex[node] = optimal;
	ChainParent[optimal] = parent;
	for (auto it : Graph[node])
		if (it != parent && ChainIndex[it] != optimal)
			ChainParent[ChainIndex[it]] = node;
}

inline void HeavyPathDecomposition (void)
{
	DepthFirstSearch(1,1,1);
	int i, j;
	for (i = 1 ; i <= Chains ; ++i)
	{
		std::reverse(Chain[i].begin(),Chain[i].end());
		for (j = 0 ; j < Chain[i].size() ; ++j)
			Position[Chain[i][j]] = j;
		ItIndex[i] = ItIndex[i - 1] + (Chain[i - 1].size() << 2);
	}
}

inline int Left_son (const int INDEX)
{
	return (INDEX << 1) + 1;
}

inline int Right_son (const int INDEX)
{
	return (INDEX << 1) + 2;
}

inline int Max (const int A, const int B)
{
	return (Value[A] > Value[B] ? A : B);
}

void ItBuild (int index, int left, int right, int chain)
{
	if (left == right)
	{
		It[index + ItIndex[chain]] = Chain[chain][left];
		return;
	}
	int mid((left + right) >> 1);
	ItBuild(Left_son(index),left,mid,chain);
	ItBuild(Right_son(index),mid + 1,right,chain);
	It[index + ItIndex[chain]] = Max(It[Left_son(index) + ItIndex[chain]],It[Right_son(index) + ItIndex[chain]]);
}

inline void Build (void)
{
	for (int i(1) ; i <= Chains ; ++i)
		ItBuild(0,0,Chain[i].size() - 1,i);
}

void ItUpdate (int index, int left, int right, int pos, int jump)
{
	if (left == right)
		return;
	int mid((left + right) >> 1);
	if (pos <= mid)
		ItUpdate(Left_son(index),left,mid,pos,jump);
	else
		ItUpdate(Right_son(index),mid + 1,right,pos,jump);
	It[index + jump] = Max(It[Left_son(index) + jump],It[Right_son(index) + jump]);
}

inline void Update (int x, int y)
{
	Value[x] = y;
	ItUpdate(0,0,Chain[ChainIndex[x]].size() - 1,Position[x],ItIndex[ChainIndex[x]]);
}

int ItQuery (int index, int left, int right, int ql, int qr, int jump)
{
	if (ql <= left && right <= qr)
		return It[index + jump];
	int mid((left + right) >> 1), max(0);
	if (ql <= mid)
		max = ItQuery(Left_son(index),left,mid,ql,qr,jump);
	if (qr > mid)
		max = Max(max,ItQuery(Right_son(index),mid + 1,right,ql,qr,jump));
	return max;
}

inline int Query (int x, int y)
{
	int result(0);
	while (true)
	{
		if (ChainIndex[x] == ChainIndex[y])
		{
			if (Position[x] > Position[y])
				std::swap(x,y);
			result = Max(result,ItQuery(0,0,Chain[ChainIndex[x]].size() - 1,Position[x],Position[y],ItIndex[ChainIndex[x]]));
			break;
		}
		if (Level[ChainParent[ChainIndex[x]]] < Level[ChainParent[ChainIndex[y]]])
			std::swap(x,y);
		if (ChainParent[ChainIndex[x]] == y || ChainParent[ChainIndex[y]] == x)
		{
			if (ChainParent[ChainIndex[x]] == y)
				std::swap(x,y);
			result = Max(result,x);
			result = Max(result,ItQuery(0,0,Chain[ChainIndex[y]].size() - 1,0,Position[y],ItIndex[ChainIndex[y]]));
			break;
		}
		result = Max(result,ItQuery(0,0,Chain[ChainIndex[x]].size() - 1,0,Position[x],ItIndex[ChainIndex[x]]));
		x = ChainParent[ChainIndex[x]];
	}
	return result;
}

int main (void)
{
	std::freopen("heavypath.in","r",stdin);
	std::freopen("heavypath.out","w",stdout);
	Read();
	HeavyPathDecomposition();
	Build();
	int t, x, y;
	while (m)
	{
		std::scanf("%d %d %d",&t,&x,&y);
		if (t == 0)
			Update(x,y);
		else if (t == 1)
			std::printf("%d\n",Value[Query(x,y)]);
		--m;
	}
	std::fclose(stdin);
	std::fclose(stdout);
	return 0;
}