Cod sursa(job #2986025)

Utilizator andrei_C1Andrei Chertes andrei_C1 Data 27 februarie 2023 16:10:37
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.78 kb
#include <bits/stdc++.h>

using namespace std;

ifstream fin("heavypath.in");
ofstream fout("heavypath.out");

const int NMAX = 1e5;

int n, m;
int v[NMAX + 1];
vector<int> adj[NMAX + 1];
int sz[NMAX + 1], heavyChild[NMAX + 1], lvl[NMAX + 1], par[NMAX + 1];

void dfs(int u = 1, int v = 0) {
	sz[u] = 1;

	for(const auto &it: adj[u]) if(it != v) {
		par[it] = u;
		lvl[it] = lvl[u] + 1;
		dfs(it, u);
		sz[u] += sz[it];
		if(sz[it] > sz[heavyChild[u]]) {
			heavyChild[u] = it;
		}
	}
}

int lbl[NMAX + 1]; // lbl[i] =def= numarul de ordine al lantului din care face parte nodul i, lbl[u] == lbl[v] <=> u si v sunt in acelasi lant (dupa descompunere), a nu se confunda cu lvl!!!
vector<int> head = {1}; // head[i] =def= capul lantului (lantul cu numarul de ordine i) format din nodurile u, etichetate cu lbl[u] = i, initial radacina este capul primului lant.
vector<int> heavyFirst;
int tin[NMAX + 1]; // tin[i] =def= pozitia (timpul de intrare) nodului i in parcurgerea heavyFirst.

void decomp(int u = 1, int v = 0) {
	heavyFirst.emplace_back(u);
	tin[u] = heavyFirst.size() - 1;
	lbl[u] = head.size() - 1;

	if(heavyChild[u] != 0) {
		decomp(heavyChild[u], u);
	}
	for(const auto &it: adj[u]) if(it != v && it != heavyChild[u]) {
		head.emplace_back(it); // lant nou -> cap nou -> eticheta noua.
		decomp(it, u);
	}
}

void maxSelf(int &x, int y) {
	if(y > x) {
		x = y;
	}
}

int segTree[2 * NMAX + 1];

void build() {
	for(int i = 0; i < n; i++) {
		segTree[n + i] = v[heavyFirst[i]];
	}
	for(int i = n - 1; i >= 1; i--) {
		segTree[i] = max(segTree[i << 1], segTree[i << 1 | 1]);
	}
}

void update(int pos, int val) {
	pos += n;
	segTree[pos] = val;
	pos >>= 1;

	while(pos >= 1) {
		segTree[pos] = max(segTree[pos << 1], segTree[pos << 1 | 1]);
		pos >>= 1;
	}
}

int query(int a, int b) {
	if(a > b) {
		swap(a, b);
	}

	int ret = 0;
	a += n;
	b += n;

	while(a <= b) {
		if(a & 1) {
			maxSelf(ret, segTree[a]);
			a++;
		}
		if(!(b & 1)) {
			maxSelf(ret, segTree[b]);
			b--;
		}

		a >>= 1;
		b >>= 1;
	}

	return ret;
}

int chainQuery(int u, int v) {
	int ret = 0;

	while(lbl[u] != lbl[v]) {
		if(lvl[head[lbl[u]]] > lvl[head[lbl[v]]]) {
			maxSelf(ret, query(tin[u], tin[head[lbl[u]]]));
			u = par[head[lbl[u]]];
		} else {
			maxSelf(ret, query(tin[v], tin[head[lbl[v]]]));
			v = par[head[lbl[v]]];
		}
	}
	maxSelf(ret, query(tin[u], tin[v]));

	return ret;
}

int main() {
	ios_base :: sync_with_stdio(false);

	fin >> n >> m;

	for(int i = 1; i <= n; i++) {
		fin >> v[i];
	}

	for(int i = 1; i < n; i++) {
		int u, v;
		fin >> u >> v;

		adj[u].emplace_back(v);
		adj[v].emplace_back(u);
	}

	dfs();
	decomp();
	build();

	for(int i = 1; i <= m; i++) {
		int t, x, y;
		fin >> t >> x >> y;
		
		if(t == 0) {
			update(tin[x], y);
		} else {
			fout << chainQuery(x, y) << '\n';
		}
	}

	fin.close();
	fout.close();
	return 0;
}