Cod sursa(job #1266631)

Utilizator DuxarFII-Stefan-Negrus Duxar Data 18 noiembrie 2014 22:49:23
Problema Heavy Path Decomposition Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 4.36 kb
#include <vector>
#include <fstream>
#include <cstdio>
#include <queue>
#include <climits>
#include <iostream>

#define pb push_back

using namespace std;


class Node {
public:
	int value, heavy, pos, path, level;

	Node() {
		heavy = 1;
		level = 1;
	}
};


int N, M, nrPaths, whichPath = 1;
vector <vector <int> > graph, decPath, segmentTree;
vector <Node> nodes;

void dfs_sum(int iam, int from = 0);
void dfs_paths(int iam, int from, int path);
void make_trees();
void insert_segment_tree(vector <int> &tree, int node, int alpha, int omega, int locus, int value);
int query_segment_tree(vector <int> &tree, int node, int alpha, int omega, int queryAlpha, int queryOmega);

int main() {
#ifdef INFOARENA
	freopen("heavypath.in", "r", stdin);
	freopen("heavypath.out", "w", stdout);
#else
	freopen("input", "r", stdin);
#endif

	int i, from, to, t, x, y, rez, path;
	basic_ios<char>::sync_with_stdio(false);
	scanf("%d %d", &N, &M);
	graph.resize(N + 1);
	nodes.resize(N + 1);

	for (i = 1; i <= N; ++i) {
		// scanf("%d", &nodes[i].value);
		cin >> nodes[i].value;
	}
	nodes[0].level = 0;

	for (i = 1; i < N; ++i) {
		// scanf("%d %d", &from, &to);
		cin >> from >> to;
		graph[from].push_back(to);
		graph[to].push_back(from);
	}


	dfs_sum(1);
	decPath.resize(nrPaths + 1);
	segmentTree.resize(nrPaths + 1);
	dfs_paths(1, 0, whichPath);
	make_trees();

	for (i = 0; i < M; ++i) {
		// scanf("%d %d %d", &t, &x, &y);
		cin >> t >> x >> y;
		if (t == 0) {
			path = nodes[x].path;
			insert_segment_tree(segmentTree[path], 1, 1, (int) decPath[path].size() - 1, nodes[x].pos, y);
		}
		else {
			rez = 0;
			while (nodes[x].path != nodes[y].path) {
				if (nodes[decPath[nodes[x].path][0]].level > nodes[decPath[nodes[y].path][0]].level) {
					path = nodes[x].path;
					rez = max(rez, query_segment_tree(segmentTree[path], 1, 1, (int) decPath[path].size() - 1, 1, nodes[x].pos));
					x = decPath[path][0];
				}
				else {
					path = nodes[y].path;
					rez = max(rez, query_segment_tree(segmentTree[path], 1, 1, (int) decPath[path].size() - 1, 1, nodes[y].pos));
					y = decPath[path][0];
				}
			}
			path = nodes[x].path;
			from = min(nodes[x].pos, nodes[y].pos);
			to = max(nodes[x].pos, nodes[y].pos);
			rez = max(rez, query_segment_tree(segmentTree[path], 1, 1, (int) decPath[path].size() - 1, from, to));
			printf("%d\n", rez);
		}
	}

	return 0;
}

void dfs_sum(int iam, int from) {
	if (graph[iam].size() == 1 && from > 0) {
		++nrPaths;
		return;
	}
	for (auto to: graph[iam]) {
		if (to != from) {
			dfs_sum(to, iam);
			nodes[iam].heavy += nodes[to].heavy;
		}
	}
}

void dfs_paths(int iam, int from, int path) {
	if (decPath[path].size() == 0) {
		decPath[path].push_back(from);
	}
	decPath[path].push_back(iam);
	nodes[iam].level = nodes[from].level + 1;
	nodes[iam].path = path;
	nodes[iam].pos = (int) decPath[path].size() - 1;

	if (graph[iam].size() > 0) {
		int _pos = -1, _max = 0;
		for (auto to: graph[iam]) {
			if (to != from) {
				if (nodes[to].heavy > _max) {
					_max = nodes[to].heavy;
					_pos = to;
				}
			}
		}
		for (auto to: graph[iam]) {
			if (to != from && to != _pos) {
				++whichPath;
				dfs_paths(to, iam, whichPath);
			}
		}

		if (_pos > 0) {
			dfs_paths(_pos, iam, path);
		}
	}
}

void make_trees() {
	int i, sz, j;
	for (i = 1; i <= nrPaths; ++i) {
		sz = (int) decPath[i].size();
		segmentTree[i].resize(sz * 4);
		for (j = 1; j < sz; ++j) {
			insert_segment_tree(segmentTree[i], 1, 1, sz - 1, j, nodes[decPath[i][j]].value);
		}
	}
}

int query_segment_tree(vector <int> &tree, int node, int alpha, int omega, int queryAlpha, int queryOmega) {
	if (queryAlpha <= alpha && omega <= queryOmega) {
		return tree[node];
	}
	int centro = (alpha + omega) / 2, rez1 = 0, rez2 = 0;
	if (queryAlpha <= centro) {
		rez1 = query_segment_tree(tree, node * 2, alpha, centro, queryAlpha, queryOmega);
	}
	if (centro < queryOmega) {
		rez2 = query_segment_tree(tree, node * 2 + 1, centro + 1, omega, queryAlpha, queryOmega);
	}
	return max(rez1, rez2);
}


void insert_segment_tree(vector <int> &tree, int node, int alpha, int omega, int locus, int value) {
	if (alpha == omega && omega == locus) {
		tree[node] = value;
		return;
	}
	int centro = (alpha + omega) / 2;
	if (locus <= centro) {
		insert_segment_tree(tree, node * 2, alpha, centro, locus, value);
	}
	else {
		insert_segment_tree(tree, node * 2 + 1, centro + 1, omega, locus, value);
	}

	tree[node] = max(tree[node * 2], tree[node * 2 + 1]);
}