Cod sursa(job #616435)

Utilizator dacyanMujdar Dacian dacyan Data 12 octombrie 2011 16:26:35
Problema Heavy Path Decomposition Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 4.84 kb
#include <fstream>
#include <vector>
#include <algorithm>
#define DIM 101000
#define DIM_LOG 2200
using namespace std;

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

class Muchie {
public:
	int id;
	int jos;
	int sus;
	vector<int> membrii;
	int D[DIM_LOG];
	void Adauga (int nod, int son);
	int Query(int, int, int, int, int); // returneaza maximul pe interval
	void Update(int, int, int, int);
	void Build(int, int, int);
};

int n, Q;
vector<int> G[DIM]; // graf initial
int v[DIM], t[DIM];

Muchie muchii[DIM_LOG]; // heavypaths
int muc[DIM], nr_muc; // din ce muchie face parte nodul
int item[DIM]; // ce pozitie ocupa i in muchii[muc[i]].membrii

int s[DIM]; // cate noduri are subarborele i
int poz, x, y, j, timp;
int in[DIM], out[DIM]; // timpii de decoperire
vector<bool> f;

void Read();
void DF1(int);
void DF(int);
int Drum(int, int); // returneaza maximul intre x si y
bool Is_ancestor(int, int);


int main()
{
	Read();
	f.resize(n+1);
	DF1(1);
	DF(1);
	for (int i = 1; i <= nr_muc; ++i)
	    muchii[i].Build(1, 0, muchii[i].membrii.size() - 1 );
	int x, y;
	bool k;
	for (int i = 1; i <= Q; ++i)
	{
		fin >> k >> x >> y;
		if (k) fout << Drum(x, y) << '\n';
		else 
		{
			v[x] = y;
			if (muc[x]) muchii[muc[x]].Update(item[x], 1, 0, muchii[muc[x]].membrii.size() - 1);
		}
	}

	fin.close();
	fout.close();
	return 0;
}

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

void DF1(int nod)
{
	if (in[nod]) return;
	in[nod] = ++timp;
	s[nod] = 1;
	for (int i = 0; i < G[nod].size(); ++i)
	{
		int son = G[nod][i];
		if (in[son]) continue;
		DF1(son);
		t[son] = nod;
		s[nod] += s[son];
	}
	out[nod] = ++timp;
}

void DF(int nod)
{
	if (f[nod]) return;
	f[nod] = 1;
	
	for (int i = 0; i < G[nod].size(); ++i)
	{
		int son = G[nod][i];
		if (f[son]) continue;
		
		if (s[son] >= s[nod] / 2)
		{
			if (muc[nod]) muchii[muc[nod]].Adauga(nod, son); // il adaug pe son la muchia tatalui
			else
			{
				nr_muc++;
				muchii[nr_muc].Adauga(nod, son); // creez alta muchie heavy (nod-son)
			}
		}
		DF(son);
	}
}

int Drum(int x, int y)
{
	if (x == y) return v[x];
	if (Is_ancestor(x,y)) return Drum(y,x); 
	if (muc[x]) // x este pe un heavy path (3 variante)
	{
		int capat = muchii[muc[x]].sus; 
		if (muc[x] == muc[y]) // sunt pe acelasi heavy path
			return muchii[muc[x]].Query(item[x], item[y], 1, 0, muchii[muc[x]].membrii.size() - 1);
		if (Is_ancestor(y, capat)) // y - e mai sus in arbore decat muc[i].sus
			return max(muchii[muc[x]].Query(item[x], item[capat], 1, 0, muchii[muc[x]].membrii.size() - 1), Drum(t[capat], y));
		
		if (Is_ancestor(capat, y)) // y este mai jos decat capat
		{
			int stramos;
			Muchie path = muchii[muc[x]];
			int st(0), dr(muchii[muc[x]].membrii.size() - 1);
			while (st <= dr)
			{
				int mij = (st + dr) / 2;
				if (Is_ancestor(path.membrii[mij], y))
				{
					stramos = path.membrii[mij];
					dr = mij - 1;
				}
				else st = mij+1;
			} // gasesc stramosul de pe heavy path a lui y care are nivel minim
			return max(muchii[muc[x]].Query(item[x], item[stramos], 1, 0, muchii[muc[x]].membrii.size() - 1), Drum(y, stramos));
		}
	}
	return max(v[x], Drum(t[x], y)); // ma duc pe light path
}

bool Is_ancestor(int x, int y)
{
	return (in[x] < in[y]) && (out[x] > out[y]);
}

int Muchie::Query(int x, int y, int nod, int st, int dr)
{
	if (y < x) swap(x,y);
	if (x <= st && y >= dr) 
	{
		return v[membrii[D[nod]]];
	}
	int mij = (st + dr) / 2;
	int aux1(0), aux2(0);
	if (x <= mij) aux1 = Query(x, y, 2*nod, st, mij);
	if (y > mij) aux2 = Query(x, y, 2*nod+1, mij+1, dr);
	return max(aux1, aux2);
}

void Muchie::Adauga(int nod, int son)
{
	if (!id) // muchie noua
	{
		id = nr_muc;
		sus = nod;
		jos = son;
		
		membrii.push_back(nod);
		item[nod] = membrii.size() - 1;
		muc[nod] = id;
	
		
		membrii.push_back(son);
		item[son] = membrii.size() - 1;
		muc[son] = id;

	}
	else // nod este deja adaugat
	{
		jos = son;
		membrii.push_back(son);
		item[son] = membrii.size() - 1;
		muc[son] = id;
	}
}

void Muchie::Update(int poz, int nod, int st, int dr)
{
	if (st == dr)
	{
		D[nod] = st;
		return;
	}
	int mij = (st + dr) / 2;
	if (poz <= mij) Update(poz,  2*nod, st, mij);
	else Update(poz, 2*nod+1, mij+1, dr);
	if (v[membrii[D[2*nod]]] > v[membrii[D[2*nod+1]]])
		D[nod] = D[2*nod];
	else D[nod] = D[2*nod+1];
}
		
void Muchie::Build(int nod, int st, int dr)
{
	if (st == dr)
	{
		D[nod] = st;
		return;
	}
	int mij = (st + dr) / 2;
    Build(2*nod, st, mij);
	Build(2*nod+1, mij+1, dr);
	if (v[membrii[D[2*nod]]] > v[membrii[D[2*nod+1]]])
		D[nod] = D[2*nod];
	else D[nod] = D[2*nod+1];
}