Cod sursa(job #1020432)

Utilizator raulstoinStoin Raul raulstoin Data 2 noiembrie 2013 02:06:01
Problema Heavy Path Decomposition Scor 10
Compilator cpp Status done
Runda Arhiva educationala Marime 3.77 kb
#include<fstream>
#include<vector>

#define NMAX 100005
#define VEC G[nod][i]
#define son (nod<<1)
#define middle ((left+right)>>1)

using namespace std;

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

int n,Q,v[NMAX],TT[NMAX],level[NMAX],k,which[NMAX],what[NMAX],TT_log[NMAX],R[NMAX];
int AINT[4*NMAX],Maxx,start[NMAX],K,first[NMAX],last[NMAX];
vector<int> G[NMAX],decomp[NMAX],GN[NMAX];
bool use[NMAX];

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

void DFS_split(int nod,int tt,int lant)
{
	TT[nod]=tt;
	level[nod]=level[tt]+1;
	first[nod]=++K;
	if(G[nod].size()==2 && nod!=1)
	{
		if(!lant)
			k++;
		lant=1;
		R[k]=max(R[k],nod);
		which[nod]=k;
		decomp[k].push_back(nod);
	}
	else
	{
		if(decomp[k].size()==1)
		{
			which[decomp[k][0]]=0;
			decomp[k].clear();
			k--;
		}
		lant=0;
	}
	for(size_t i=0;i<G[nod].size();i++)
		if(VEC!=tt)
			DFS_split(VEC,nod,lant);
	last[nod]=K;
}

void build_tree(int nod)
{
	int NN;
	if(!which[nod])
		NN=nod;
	else
		NN=R[which[nod]];
	for(size_t i=0;i<G[nod].size();i++)
		if(VEC!=TT[nod])
		{
			if(!which[VEC] || decomp[which[VEC]].size()==1)
				GN[NN].push_back(VEC);
			else
				if(!use[which[VEC]])
				{
					GN[NN].push_back(R[which[VEC]]);
					use[which[VEC]]=1;
				}
			build_tree(VEC);
		}
}

void build_father(vector<int> *G,int nod,int tt)
{
	TT_log[nod]=tt;
	level[nod]=level[tt]+1;
	for(size_t i=0;i<G[nod].size();i++)
		if(VEC!=tt)
			build_father(G,VEC,nod);
	G[nod].clear();
	::G[nod].clear();
}

inline void update(int left,int right,int nod,int val,int poz)
{
    if(left==right)
    {
        AINT[nod]=val;
        return;
    }
    if(poz<=middle)
        update(left,middle,son,val,poz);
    else
        update(middle+1,right,son+1,val,poz);
    AINT[nod]=max(AINT[son],AINT[son+1]);
}

void query(int left,int right,int nod,int L,int R)
{
	if(left>R || right<L)
		return;
	if(L<=left && right<=R)
	{
		Maxx=max(Maxx,AINT[nod]);
		return;
	}
	query(left,middle,son,L,R);
	query(middle+1,right,son+1,L,R);
}

void Max(int &A,int &maxim)
{
	Maxx=0;
	if(which[A])
	{
		query(1,n,1,start[which[A]],what[A]);
		maxim=max(maxim,Maxx);
		A=TT_log[R[which[A]]];
	}
	else
	{
		maxim=max(maxim,v[A]);
		A=TT[A];
	}
}

int LCA_split(int x,int y)
{
	int maxim=0;
	while(level[x]>level[y])
		Max(x,maxim);
	while(level[x]<level[y])
		Max(y,maxim);
	while(x!=y)
	{
		Max(x,maxim);
		Max(y,maxim);
	}
	maxim=max(maxim,v[x]);
	return maxim;
}

int main()
{
	read();
	DFS_split(1,0,0);
	for(int i=1,L=1;i<=k;i++)
	{
		start[i]=L;
		for(size_t j=0;j<decomp[i].size();j++,L++)
		{
			what[decomp[i][j]]=L;
			update(1,n,1,v[decomp[i][j]],L);
		}
		decomp[i].clear();
	}
	build_tree(1);
	build_father(GN,1,0);
	
	for(int op,x,y;Q;Q--)
	{
		fin>>op>>x>>y;
		if(!op)
		{
			if(!which[x])
				v[x]=y;
			else
				update(1,n,1,y,what[x]);
			continue;
		}
		Maxx=0;
		//acelasi nod
		if(x==y)
		{
			fout<<v[x]<<'\n';
			continue;
		}
		//acelasi grup
		if(which[x]==which[y] && which[x])
		{
			x=what[x];
			y=what[y];
			if(x>y)
				swap(x,y);
			query(1,n,1,x,y);
			fout<<Maxx<<'\n';
			continue;
		}
		
		if(first[x]>first[y])
			swap(x,y);
		//x e stramos a lui y
		if(first[y]<=last[x])
		{
			int maxim=0;
			if(which[x])
			{
				query(1,n,1,what[x],start[which[x]+1]-1);
				maxim=max(maxim,Maxx);
				x=R[which[x]];
			}
			else
				maxim=max(maxim,v[x]);
			while(TT_log[y]!=x)
				Max(y,maxim);
			Max(y,maxim);
			fout<<maxim<<'\n';
			continue;
		}
		//x si y se afla in subarbori diferiti
		else
			fout<<LCA_split(x,y)<<'\n';
	}
	
	return 0;
}