Cod sursa(job #2151903)

Utilizator RazvanR104Razvan-Andrei Ciocoiu RazvanR104 Data 5 martie 2018 05:38:53
Problema Heavy Path Decomposition Scor 0
Compilator cpp Status done
Runda Arhiva educationala Marime 4.24 kb
#include <bits/stdc++.h>

using namespace std;

const int NMAX = 100010;

int N, M, currPath;
int values[NMAX];
int size[NMAX], where[NMAX], pathFather[NMAX], level[NMAX], pathPos[NMAX];
vector<int> T[NMAX], path[NMAX];

struct Node {
	int value, size, maxVal, priority;
	Node *left, *right;
	Node(int value, int size, int maxVal, int priority, Node *left, Node *right):
		value(value),
		size(size),
		maxVal(maxVal),
		priority(priority),
		left(left),
		right(right) {
	}
} *nil, *root[NMAX];

void heavyDFS(int node, int father, int currLevel) {
	size[node] = 1;
	level[node] = currLevel;
	if (T[node].size() == 1 && father != -1) {
		where[node] = currPath;
		path[currPath].push_back(node);
		pathPos[node] = path[currPath++].size() - 1;
		return;
	}

	int maxSubtree = -1;
	for (int i: T[node]) {
		if (i == father)
			continue;
		heavyDFS(i, node, currLevel + 1);
		size[node] += size[i];
		if (maxSubtree == -1 || size[maxSubtree] < size[i])
			maxSubtree = i;
	}

	path[where[maxSubtree]].push_back(node);
	pathPos[node] = path[where[maxSubtree]].size() - 1;
	where[node] = where[maxSubtree];

	for (int i: T[node]) {
		if (i == maxSubtree || i == father)
			continue;
		pathFather[where[i]] = node;
	}
}

void updateNode(Node *curr) {
	if (curr == nil)
		return;
	curr->maxVal = max(curr->value, max(curr->left->maxVal, curr->right->maxVal));
	curr->size = curr->left->size + curr->right->size + 1;
}

Node *joinTreaps(Node *left, Node *right) {
	if (left == nil)
		return right;
	if (right == nil)
		return left;
	if (left->priority > right->priority) {
		Node *temp = joinTreaps(left->right, right);
		left->right = temp;
		updateNode(left);
		return left;
	}
	Node *temp = joinTreaps(left, right->left);
	right->left = temp;
	updateNode(right);
	return right;
}

pair<Node *, Node *> splitTreaps(Node *node, int pos) {
	if (node == nil)
		return {nil, nil};
	if (pos == node->left->size + 1) {
		Node *temp = node->right;
		node->right = nil;
		updateNode(node);
		return {node, temp};
	}
	if (pos < node->left->size + 1) {
		auto split = splitTreaps(node->left, pos);
		node->left = split.second;
		updateNode(node);
		return {split.first, node};
	}
	auto split = splitTreaps(node->right, pos - node->left->size - 1);
	node->right = split.first;
	updateNode(node);
	return {node, split.second};
}

int maxValue(Node *&node, int x, int y) {
	if (x > y)
		swap(x, y);
	++x, ++y;
	auto split1 = splitTreaps(node, x - 1);
	auto split2 = splitTreaps(split1.second, y - x + 1);
	int answer = split2.first->maxVal;
	node = joinTreaps(split1.first, split2.first);
	node = joinTreaps(node, split2.second);
	return answer;
}

void updateValue(Node *node, int value, int pos) {
	if (node == nil)
		return;
	if (pos == node->left->size + 1) {
		node->value = value;
		updateNode(node);
		return;
	}
	if (pos < node->left->size + 1)
		updateValue(node->left, value, pos);
	else
		updateValue(node->right, value, pos - 1 - node->left->size);
	updateNode(node);
}

int main() {
	assert(freopen("heavypath.in", "r", stdin));
	assert(freopen("heavypath.out", "w", stdout));

	int i;

	cin >> N >> M;
	for (i = 1; i <= N; ++i)
		cin >> values[i];
	for (i = 0; i < N - 1; ++i) {
		int x, y;
		cin >> x >> y;
		T[x].push_back(y);
		T[y].push_back(x);
	}

	heavyDFS(1, -1, 0);

	srand(time(0));
	nil = new Node(numeric_limits<int>::min(), 0, numeric_limits<int>::min(), -1, nullptr, nullptr);
	nil->left = nil->right = nil;
	for (i = 0; i < currPath; ++i) {
		root[i] = nil;
		for (int j: path[i]) {
			Node *temp = new Node(values[j], 1, values[j], rand(), nil, nil);
			root[i] = joinTreaps(root[i], temp);
		}
	}

	while (M--) {
		int opType, x, y;
		cin >> opType >> x >> y;
		if (opType == 0) {
			updateValue(root[where[x]], y, pathPos[x] + 1);
		} else {
			int answer = numeric_limits<int>::min();
			while (where[x] != where[y]) {
				if (level[pathFather[where[x]]] < level[pathFather[where[y]]])
					swap(x, y);
				answer = max(answer, maxValue(root[where[x]], pathPos[x], path[where[x]].size() - 1));
				x = pathFather[where[x]];
			}
			answer = max(answer, maxValue(root[where[x]], pathPos[x], pathPos[y]));
			cout << answer << '\n';
		}
	}

	return 0;
}