Cod sursa(job #2151906)

Utilizator RazvanR104Razvan-Andrei Ciocoiu RazvanR104 Data 5 martie 2018 05:56:02
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.74 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];

class Reader {
public:
	Reader(const string& filename):
		m_stream(filename),
		m_pos(kBufferSize - 1),
		m_buffer(new char[kBufferSize]) {
		next();
	}
	Reader& operator>>(int& value) {
		value = 0;
		while (current() < '0' || current() > '9')
			next();
		while (current() >= '0' && current() <= '9') {
			value = value * 10 + current() - '0';
			next();
		}
		return *this;
	}
private:
	const int kBufferSize = 32768;
	char current() {
		return m_buffer[m_pos];
	}
	void next() {
		if (!(++m_pos != kBufferSize)) {
			m_stream.read(m_buffer.get(), kBufferSize);
			m_pos = 0;
		}
	}
	ifstream m_stream;
	int m_pos;
	unique_ptr<char[]> m_buffer;
};

class Writer {
public:
	Writer(const char *name):
		m_stream(name) {
		memset(m_buffer, 0, sizeof(m_buffer));
		m_pos = 0;
	}
	Writer& operator<<(int a) {
		int many = 0;
		do {
			digit_buffer[many++] = a % 10 + '0';
			a /= 10;
		} while (a > 0);
		for (int i = many - 1; i >= 0; --i)
			putchar(digit_buffer[i]);
		return *this;
	}
	Writer& operator<<(const char *s) {
		for (; *s; ++s)
			putchar(*s);
		return *this;
	}
	~Writer() {
		m_stream.write(m_buffer, m_pos);
	}
private:
	void putchar(char c) {
		m_buffer[m_pos++] = c;
		if (m_pos == kBufferSize) {
			m_stream.write(m_buffer, m_pos);
			m_pos = 0;
		}
	}
	static const int kBufferSize = 32768;
	ofstream m_stream;
	char m_buffer[kBufferSize];
	char digit_buffer[30];
	int m_pos;
};

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() {
	Reader fin("heavypath.in");
	Writer fout("heavypath.out");

	int i;

	fin >> N >> M;
	for (i = 1; i <= N; ++i)
		fin >> values[i];
	for (i = 0; i < N - 1; ++i) {
		int x, y;
		fin >> 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);
		}
	}

	level[0] = numeric_limits<int>::min();
	while (M--) {
		int opType, x, y;
		fin >> opType >> x >> y;
		if (opType == 0) {
			updateValue(root[where[x]], y, pathPos[x] + 1);
		} else {
			int answer = numeric_limits<int>::min();
			while ((x != 0 || y != 0) && 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]];
			}
			if (x != 0 || y != 0)
				answer = max(answer, maxValue(root[where[x]], pathPos[x], pathPos[y]));
			fout << answer << "\n";
		}
	}

	return 0;
}