Cod sursa(job #1001111)

Utilizator ELHoriaHoria Cretescu ELHoria Data 24 septembrie 2013 15:29:53
Problema Heavy Path Decomposition Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 3.55 kb
#include <fstream>
#include <vector>
#include <algorithm>

#define REP(i,n) for(int i = 0;i < (int)n;i++)

using namespace std;

ifstream cin("heavypath.in");
ofstream cout("heavypath.out");

const int nmax = int(1e5) + 2;
int n, m;
int value[nmax];
int level[nmax];
int weight[nmax];
int nodeIndex[nmax];
int pathParent[nmax];
int nodePath[nmax];
int pathNumber;
vector< vector<int> > paths, segmentTrees;
vector<int> G[nmax];


inline void readData() {
	cin>>n>>m;
	for(int i = 1;i <= n;i++) {
		cin>>value[i];
	}
	int a, b;
	for(int i = 1;i < n;i++) {
		cin>>a>>b;
		G[a].push_back(b);
		G[b].push_back(a);
	}
}

void df(int v,int vp) {
	weight[v] = 1;
	int heavyestSon = -1;
	for(auto w : G[v]) {
		if(w == vp) continue;
		level[w] = level[v] + 1;
		df(w,v); 
		weight[v] += weight[w];
		if(heavyestSon == -1 || weight[heavyestSon] < weight[w]) {
			heavyestSon = w;
		}
	}

	if(heavyestSon == -1) {
		paths.push_back(vector<int>());
		paths.back().push_back(v);
		nodePath[v] = pathNumber++;
	} else {
		nodePath[v] = nodePath[heavyestSon];
		paths[nodePath[v]].push_back(v);
		for(auto w : G[v]) {
			if(w == vp || w == heavyestSon) continue;
			pathParent[nodePath[w]] = v;
		}
	}
}

void buildTree(const int &treeIndex,int node,int l,int r) {
	if(l > r) return;
	if(l == r) {
		segmentTrees[treeIndex][node] = value[paths[treeIndex][l - 1]];
		return;
	}
	int mid = (l + r)>>1;
	buildTree(treeIndex,node<<1,l,mid);
	buildTree(treeIndex,node<<1 | 1,mid + 1,r);
	segmentTrees[treeIndex][node] = max(segmentTrees[treeIndex][node<<1],segmentTrees[treeIndex][node<<1 | 1]);
}

inline void buildTrees() {
	REP(i,pathNumber) {
		reverse(paths[i].begin(),paths[i].end());
		REP(j,paths[i].size()) {
			nodeIndex[paths[i][j]] = j + 1;
		}
		segmentTrees.push_back(vector<int>(paths[i].size()<<2,0));
		buildTree(i,1,1,paths[i].size());
	}
}

void updateTree(const int &treeIndex,int node,int l,int r,int pos) {
	if(l == r) {
		if(l == pos) {
			segmentTrees[treeIndex][node] = value[paths[treeIndex][l - 1]];
		
		}
		return;
	}
	int mid = (l + r)>>1;
	pos <= mid ? updateTree(treeIndex,node<<1,l,mid,pos) : updateTree(treeIndex,node<<1 | 1,mid + 1,r,pos);
	segmentTrees[treeIndex][node] = max(segmentTrees[treeIndex][node<<1],segmentTrees[treeIndex][node<<1 | 1]);
}

inline void update(const int &v,const int &newValue) {
	value[v] = newValue;
	updateTree(nodePath[v],1,1,paths[nodePath[v]].size(),nodeIndex[v]);
}

int queryTree(const int &treeIndex,int node,int l,int r,const int &ql,const int &qr) {
	if(r < ql || l > qr ) return 0;
	if(ql <= l && r <= qr) {
		return segmentTrees[treeIndex][node];
	}
	int mid = (l + r)>>1;
	return max(queryTree(treeIndex,node<<1,l,mid,ql,qr),queryTree(treeIndex,node<<1 | 1,mid + 1,r,ql,qr));
}

int query(int a,int b) {
	if(a == b) {
		return value[a];
	}
	
	if(nodePath[a] == nodePath[b]) {
		int posA = nodeIndex[a];
		int posB = nodeIndex[b];
		if(posA > posB) swap(posA,posB);
		return queryTree(nodePath[a],1,1,paths[nodePath[a]].size(),posA,posB);
	}

	if(level[pathParent[nodePath[a]]] > level[pathParent[nodePath[b]]]) {
		return max(query(pathParent[nodePath[a]],b),queryTree(nodePath[a],1,1,paths[nodePath[a]].size(),1,nodeIndex[a]));
	}

	return max(query(pathParent[b],a),queryTree(nodePath[b],1,1,paths[nodePath[b]].size(),1,nodeIndex[b]));
}

int main()
{
	readData();

	df(1,1);

	buildTrees();

	for(int t, a, b;m;m--) {
		cin>>t>>a>>b;
		if(!t) {
			update(a,b);
		} else {
			cout<<query(a,b)<<"\n";
		}
	}
    return 0;
}