Cod sursa(job #1198656)

Utilizator howsiweiHow Si Wei howsiwei Data 16 iunie 2014 16:06:03
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 3.3 kb
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define PATH(u) paths[pathof[u]]
typedef pair<int, int> II;

vector<int> a;
vector<vector<int>> adjl;
vector<int> parent;
vector<int> level;
vector<int> leaf;
vector<int> pathof;
vector<int> index;

class Path
{
	int n;
	vector<vector<int>> t;
public:
	int root;
	Path() {}
	Path(int leaf, int root, int n) : n(n), root(root)
	{
		t.assign(2, vector<int>(n+1));
		for (int i = n, u = leaf; i >= 1; u = parent[u], i--) {
			t[1][i] = a[u];
		}
		for (int stp = 2; stp <= n; stp *= 2) {
			for (int i = stp; i <= n; i += stp) {
				t[0][i-stp/2] = t[1][i];
				t[1][i] = max(t[1][i-stp/2], t[1][i]);
			}
		}
	}
	int getmax(int lo, int hi)
	{
		hi++;
		int res = 0;
		if (lo != 0) {
			while (lo + (lo & -lo) <= hi) {
				res = max(res, t[0][lo]);
				lo += lo & -lo;
			}
		}
		while (hi != lo) {
			res = max(res, t[1][hi]);
			hi &= hi-1;
		}
		return res;
	}
	void update(int idx, int val)
	{
		int lo = idx;
		int hi = idx+1;
		while (hi <= n) {
			if ((lo & -lo) > (hi & -hi) || lo == 0) {
				if (t[1][hi] == val) {
					break;
				}
				t[1][hi] = val;
				val = max(t[0][hi], t[1][hi]);
				hi += hi & -hi;
			}
			else {
				if (t[0][lo] == val) {
					break;
				}
				t[0][lo] = val;
				val = max(t[0][lo], t[1][lo]);
				lo &= lo-1;
			}
		}
	}
};

vector<Path> paths;

void build_path(int l, int r)
{
	int len = 0;
	for (int u = l; ; u = parent[u], len++) {
		pathof[u] = paths.size();
		index[u] = len;
		if (u == r) {
			len++;
			break;
		}
	}
	for (int u = l, i = len-1; i >= 0; u = parent[u], i--) {
		index[u] = i;
	}
	paths.emplace_back(l, r, len);
}

int build_heavy_paths(int u)
{
	int size = 1;
	if (adjl[u].size() == (u == 0 ? 0 : 1)) {
		leaf[u] = u;
	}
	else {
		II heaviest = {0, 0};
		for (auto v: adjl[u]) {
			if (v == parent[u]) {
				continue;
			}
			parent[v] = u;
			level[v] = level[u]+1;
			int subsize = build_heavy_paths(v);
			size += subsize;
			heaviest = max(heaviest, {subsize, v});
		}
		leaf[u] = leaf[heaviest.second];
		for (auto v: adjl[u]) {
			if (v == parent[u] || v == heaviest.second) {
				continue;
			}
			else {
				build_path(leaf[v], v);
			}
		}
	}
	if (u == 0) {
		build_path(leaf[u], u);
	}
	return size;
}

int getmax(int u, int v)
{
	int res = 0;
	while (pathof[u] != pathof[v]) {
		if (level[PATH(u).root] > level[PATH(v).root]) {
			swap(u, v);
		}
		res = max(res, PATH(v).getmax(0, index[v]));
		v = parent[PATH(v).root];
	}
	II x = minmax(index[u], index[v]);
	res = max(res, PATH(v).getmax(x.first, x.second));
	return res;
}

void update(int u, int val)
{
	PATH(u).update(index[u], val);
}

int main()
{
	ios::sync_with_stdio(false);
	freopen("heavypath.in", "r", stdin);
	freopen("heavypath.out", "w", stdout);
	int n, m;
	cin >> n >> m;
	a.resize(n);
	for (auto & x: a) {
		cin >> x;
	}
	adjl.resize(n);
	for (int i = 0; i < n-1; i++) {
		int u, v;
		cin >> u >> v;
		u--, v--;
		adjl[u].push_back(v);
		adjl[v].push_back(u);
	}
	parent.resize(n);
	parent[0] = -1;
	level.resize(n);
	leaf.resize(n);
	pathof.resize(n);
	index.resize(n);
	build_heavy_paths(0);
	for (int i = 0; i < m; i++) {
		int op;
		cin >> op;
		if (op == 0) {
			int u, val;
			cin >> u >> val;
			u--;
			update(u, val);
		}
		else {
			int u, v;
			cin >> u >> v;
			u--, v--;
			printf("%d\n", getmax(u, v));
		}
	}
	return 0;
}