Cod sursa(job #611836)

Utilizator vlad.maneaVlad Manea vlad.manea Data 3 septembrie 2011 18:35:44
Problema Heavy Path Decomposition Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 5.74 kb
#include <algorithm>
#include <cstdio>
#include <vector>
#include <list>

#define IN "heavypath.in"
#define OUT "heavypath.out"
#define NMax 100000
using namespace std;

int N, M;

// vals of nodes
vector<int> Val;

// adiacency list
vector<int> Nei[NMax];

// levels of nodes
vector<int> Lev;

// sizes of nodes
vector<int> Siz;

// chains of nodes
vector<int> Cha;

// first of chains
vector<int> Fir;

// boss of chain
vector<int> Bos;

// chains
vector< vector<int> > CSet;

// trees
vector< vector<int> > STree;

// get position
inline int position(const int &x)
{
	// return position
	return Lev[x] - Lev[Fir[Cha[x]]];
}

// query tree
int queryTree(const int &c, const int &n, const int &l, const int &r, const int &px, const int &py)
{
	// is it outside the border?
	if (px > r || py < l)
		return -1;

	// is it a contiguous node?
	if (px <= l && r <= py)
		return STree[c][n];

	// get middle
	int m = (l + r) >> 1;

	// get the left and right values
	int lv = queryTree(c, n << 1 | 1, l, m, px, py);
	int rv = queryTree(c, (n + 1) << 1, m + 1, r, px, py);

	// return the maximum
	return max(lv, rv);
}

// change
inline void change (int &x, int &y)
{
	int z;
	z = x;
	x = y;
	y = z;
}

// query
int query(const int &x, const int &y)
{
	// check for same node
	if (x == y) return Val[x];

	// get chains of x and y
	int cx = Cha[x], cy = Cha[y];

	// are they of the same chain?
	if (cx == cy)
	{
		// get positions
		int px = position(x), py = position(y);

		// return the minimum
		return queryTree(cx, 0, 0, CSet[cx].size() - 1, min(px, py), max(px, py));
	}

	// get qquery
	int qquery = Lev[Bos[cx]] > Lev[Bos[cy]]? 
		query(Bos[cx], y): 
		query(Bos[cy], x);

	// get tquery
	int tquery = Lev[Bos[cx]] > Lev[Bos[cy]]? 
		queryTree(cx, 0, 0, CSet[cx].size() - 1, 0, position(x)):
		queryTree(cy, 0, 0, CSet[cy].size() - 1, 0, position(y));

	// return max
	return max(qquery, tquery);
}

void updateTree(const int &c, const int &n, const int &l, const int &r, const int &p, const int &v)
{
	// is it one element
	if (l == r)
	{
		// set the value in this node
		STree[c][n] = v;

		// ok, done
		return;
	}

	// get middle
	int m = (l + r) >> 1;

	// test for left
	if (p <= m) updateTree(c, (n << 1) | 1, l, m, p, v);

	// test for right
	else updateTree(c, (n + 1) << 1, m + 1, r, p, v);

	// set maximum value
	STree[c][n] = max(STree[c][(n << 1) | 1], STree[c][(n + 1) << 1]);
}

// set value of x to y
void update(const int &x, const int &y)
{
	// get chain of x
	int c = Cha[x];

	// update tree
	updateTree(c, 0, 0, CSet[c].size() - 1, position(x), y);
}

// level, size, parent [node] with [parent] and [level]
void levelSizeParent(const int &n, const int &p, const int &l)
{
	int c, s = 0, m = 0, r = 0, d = 0;

	// set level, parent, size for current node
	Lev[n] = l, Siz[n] = 1;

	// is it a leaf?
	if (Nei[n].size() == 1 && Nei[n][0] == p)
	{
		// get size
		c = CSet.size();

		// create a new chain
		CSet.push_back(vector<int>(1, n));

		// set chain of node
		Cha[n] = c;

		// set first node of chain
		Fir.push_back(n);

		// set boss node of chain
		Bos.push_back(N);

		// ok, done with that
		return;
	}

	// iterate all neighbours
	for (int i = 0; i < Nei[n].size(); ++i)
	{
		// get child
		c = Nei[n][i];

		// is it a child?
		if (c != p)
		{
			// go to [child] with [node] and [level]
			levelSizeParent(c, n, l + 1);

			s += (d = Siz[c]);

			// set size to maximum
			if (d > m)
				m = d, r = Cha[c];
		}
	}

	// add node to chain
	CSet[r].push_back(n);

	// add childrens' sizes to node
	Siz[n] += s;

	// set first node of chain to n
	Fir[r] = n;

	// set chain of r as chain of n
	Cha[n] = r;

	// iterate all neighbours
	for (int i = 0; i < Nei[n].size(); ++i)
	{
		// get child
		c = Nei[n][i];

		// is it a child with other chain?
		if (c != p && Cha[c] != r)
			Bos[Cha[c]] = n;
	}
}

// build tree
void buildTree(const int &c, const int &n, const int &l, const int &r)
{
	// is it one element
	if (l == r)
	{
		// set the value in this node
		STree[c][n] = Val[CSet[c][l]];

		// ok, done
		return;
	}

	// get middle
	int m = (l + r) >> 1;

	// set for child nodes
	buildTree(c, (n << 1) | 1, l, m);
	buildTree(c, (n + 1) << 1, m + 1, r);

	// set maximum value
	STree[c][n] = max(STree[c][(n << 1) | 1], STree[c][(n + 1) << 1]);
}

// build a segment tree
void buildSegmentTree(const int &c)
{
	// set tree length
	int s = CSet[c].size();
	s <<= 1;

	// test 2n
	s & (s - 1)?

		// add a sized vector
		STree.push_back(vector<int>((s & (s - 1)) << 1, 0)):

		// add a sized vector
		STree.push_back(vector<int>(s, 0));

	buildTree(c, 0, 0, CSet[c].size() - 1);
}

int main()
{
	int i, a, b;

	freopen(IN, "r", stdin);
	freopen(OUT, "w", stdout);

	// read size
	scanf("%d%d", &N, &M);

	// read values O(N)
	Val.assign(N, -1);
	for (i = 0; i < N; ++i)
		scanf("%d", &Val[i]);

	// read edges O(N)
	for (i = 1; i < N; ++i)
	{
		scanf("%d%d", &a, &b);
		--a, --b;
		Nei[a].push_back(b);
		Nei[b].push_back(a);
	}

	// initialize L, P, S arrays O(N)
	Lev.assign(N, 0);
	Siz.assign(N, 0);
	Cha.assign(N, -1);

	// level, size, parent nodes O(N)
	levelSizeParent(0, -1, 0);
	Lev.push_back(-1);

	// reverse all chains to have elements by level O(NlogN)
	for (i = 0; i < CSet.size(); ++i)
	{
		reverse(CSet[i].begin(), CSet[i].end());
		buildSegmentTree(i);
	}

	// do all jobs
	while (M--)
	{
		scanf("%d%d%d", &i, &a, &b);
		
		// for the type of question
		i?

			// query in O(log(N))
			printf("%d\n", query(a - 1, b - 1)): 
		
			// update in O(log(N))
			update(i = a - 1, b);
	}	

	return 0;
}