제출 #1117135

#제출 시각아이디문제언어결과실행 시간메모리
1117135xnqsValley (BOI19_valley)C++17
32 / 100
2323 ms165536 KiB
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <utility>
#include <algorithm>
#include <tuple>
#include <set>
#include <functional>
 
enum QueryAnswer {
	AnswerEscaped = -2,
	AnswerInfinity = -1,
};
 
int gs, sh, q, dest;
std::vector<int> shops;
bool is_shop[100005];
std::vector<std::vector<std::pair<int,int>>> adj_list;
std::vector<std::tuple<int,int,int>> edges;
std::vector<std::pair<int,int>> queries[100005];
int64_t query_ans[100005];
 
int depth[100005];
int64_t dist[100005];
int par[100005];
int sp_tb_tour[18][200005];
int tin[100005];
int tout[100005];
 
int fnwk[200005];
 
void fnwk_add(int k, int val) {
	while (k < 200005) {
		fnwk[k] += val;
		k += k&-k;
	}
}
 
int fnwk_query(int pos) {
	int ret = 0;
	while (pos > 0) {
		ret += fnwk[pos];
		pos ^= pos&-pos;
	}
	return ret;
}
 
inline int fnwk_query(int l, int r) {
	return fnwk_query(r) - fnwk_query(l-1);
}
 
int dcmp_root;
std::vector<std::vector<int>> adj_list_dcmp;
std::set<std::pair<int64_t,int>> benis_in[100005]; // inside of subtree
std::set<std::pair<int64_t,int>> benis_out[100005]; // outside of subtree
int par_dcmp[100005];
 
inline int highest_node(int a, int b) {
	return ((depth[a]<=depth[b]) ? a : b);
}
 
void dfs1(int k, int p, int& timer) {
	depth[k] = depth[p]+1;
	par[k] = p;
	
	++timer;
	sp_tb_tour[0][timer] = k;
	tin[k] = tout[k] = timer;
 
	for (const auto& [i, w] : adj_list[k]) {
		if (i!=p) {
			dist[i] = dist[k]+w;
			dfs1(i,k,timer);
			++timer;
			sp_tb_tour[0][timer] = k;
			tout[k] = timer;
		}
	}
}
 
void build_sparse_table() {
	for (int l = 1; l < 18; l++) {
		for (int i = 1; i+(1<<l)-1 <= 2*gs-1; i++) {
			sp_tb_tour[l][i] = highest_node(sp_tb_tour[l-1][i],sp_tb_tour[l-1][i+(1<<(l-1))]);
		}
	}
}
 
inline int get_lca(int a, int b) {
	int l = tin[a];
	int r = tin[b];
	if (l>r) {
		std::swap(l,r);
	}
 
	int lvl = 31-__builtin_clz(r-l+1);
	return highest_node(sp_tb_tour[lvl][l],sp_tb_tour[lvl][r-(1<<lvl)+1]);
}
 
inline int64_t get_dist(int a, int b) {
	if (!a||!b) {
		return 0x3f3f3f3f3f3f3f3f;
	}
	return dist[a] + dist[b] - 2*dist[get_lca(a,b)];
}
 
void build_centroid_decomp() {
	std::vector<int> sub_sz(gs+1,0);
	std::vector<bool> blocked(gs+1,0);
 
	const std::function<int(int,int)> dfs_sz = [&](int k, int p) {
		sub_sz[k] = 1;
		for (const auto& [i, w] : adj_list[k]) {
			if (!blocked[i]&&i!=p) {
				sub_sz[k] += dfs_sz(i,k);
			}
		}
		return sub_sz[k];
	};
 
	const std::function<int(int,int,int)> dfs_centroid = [&](int k, int p, int sz) {
		for (const auto& [i, w] : adj_list[k]) {
			if (i!=p&&!blocked[i]&&sub_sz[i]>sz/2) {
				return dfs_centroid(i,k,sz);
			}
		}
		return k;
	};
 
	const std::function<void(int,int)> dfs_build = [&](int k, int p) {
		int sz = dfs_sz(k,0);
		int cen = dfs_centroid(k,0,sz);
 
		if (p) {
			//std::cout << p << " " << cen << "\n";
			adj_list_dcmp[p].emplace_back(cen);
			adj_list_dcmp[cen].emplace_back(p);
			par_dcmp[cen] = p;
		}
		else {
			dcmp_root = cen;
			//std::cout << dcmp_root << "\n";
		}
 
		blocked[cen] = 1;
		for (const auto& [i, w] : adj_list[cen]) {
			if (!blocked[i]) {
				dfs_build(i,cen);
			}
		}
	};
 
	dfs_build(1,0);
}
 
void decomp_add(std::set<std::pair<int64_t,int>>* benis, int node) {
	int k = node;
	while (k) {
		benis[k].emplace(get_dist(node,k), node);
		k = par_dcmp[k];
	}
}
 
void decomp_remove(std::set<std::pair<int64_t,int>>* benis, int node) {
	int k = node;
	while (k) {
		benis[k].erase(benis[k].lower_bound(std::pair<int64_t,int>(get_dist(node,k), node)));
		k = par_dcmp[k];
	}
}
 
int64_t decomp_query(std::set<std::pair<int64_t,int>>* benis, int node, int sub_root, int mode) {
	int k = node;
	int64_t ret = 0x3f3f3f3f3f3f3f3f;
	while (k) {
		for (const auto& [a, b] : benis[k]) {
			// the most dogshit "optimization" but its all i can think of
			if (mode^(tin[sub_root] <= tin[node] && tout[node] <= tout[sub_root])) {
				ret = std::min(ret, a + get_dist(node,k));
				break;
			}
		}
		k = par_dcmp[k];
	}
	return ret;
}
 
void dfs_solve(int k, int p) {
	for (const auto& [node, qidx] : queries[k]) {
		//std::cout << k << " " << node << " " << qidx << "\n";
		if (tin[k]<=tin[node]&&tout[node]<=tout[k]) {
			query_ans[qidx] = decomp_query(benis_in, node, k, 0);
			if (is_shop[node]) {
				query_ans[qidx] = 0;
			}
		}
		else {
			query_ans[qidx] = decomp_query(benis_out, node, k, 1);
			if (is_shop[node]) {
				query_ans[qidx] = 0;
			}
		}
	}
 
	if (is_shop[k]) {
		decomp_remove(benis_in, k);
		decomp_add(benis_out, k);
	}
	for (const auto& [i, w] : adj_list[k]) {
		if (i!=p) {
			dfs_solve(i,k);
		}
	}
	if (is_shop[k]) {
		decomp_remove(benis_out, k);
		decomp_add(benis_in, k);
	}
}
 
int main() {
	std::ios_base::sync_with_stdio(false);
	std::cin.tie(NULL);
	std::cout.tie(NULL);
 
	std::cin >> gs >> sh >> q >> dest;
	adj_list.resize(gs+1);
	adj_list_dcmp.resize(gs+1);
	edges.reserve(gs-1);
 
	for (int i = 0, a, b, c; i < gs-1; i++) {
		std::cin >> a >> b >> c;
		edges.emplace_back(a,b,c);
		adj_list[a].emplace_back(b,c);
		adj_list[b].emplace_back(a,c);
	}
 
	shops.reserve(sh);
	for (int i = 0, tmp; i < sh; i++) {
		std::cin >> tmp;
		is_shop[tmp] = 1;
		shops.emplace_back(tmp);
	}
 
	{ int timer = 0; dfs1(1,0,timer); }
	build_sparse_table();
	for (auto& [a, b, c] : edges) {
		if (depth[a]>depth[b]) {
			std::swap(a,b);
		}
	}
 
	/*for (int i = 1; i <= gs; i++) {
		std::cout << i << " " << tin[i] << " " << tout[i] << "\n";
	}*/
 
	build_centroid_decomp();
 
	for (int i = 1; i <= gs; i++) {
		benis_in[i].emplace(0x3f3f3f3f3f3f3f3f,0);
		benis_out[i].emplace(0x3f3f3f3f3f3f3f3f,0);
	}
 
	for (const auto& i : shops) {
		fnwk_add(tin[i],1);
	}
 
	for (int i = 0, edge_idx, node; i < q; i++) {
		std::cin >> edge_idx >> node; --edge_idx;
 
		//queries[std::get<1>(edges[edge_idx])].emplace_back(node, i);
 
		//std::cout << i << " " << edge_idx << " " << std::get<0>(edges[edge_idx]) << " " << std::get<1>(edges[edge_idx]) << " " << node << "\n";
		if (tin[std::get<1>(edges[edge_idx])] <= tin[node] && tout[node] <= tout[std::get<1>(edges[edge_idx])]) {
			if (tin[std::get<1>(edges[edge_idx])] <= tin[dest] && tout[dest] <= tout[std::get<1>(edges[edge_idx])]) {
				query_ans[i] = AnswerEscaped;
			}
			else if (!fnwk_query(tin[std::get<1>(edges[edge_idx])], tout[std::get<1>(edges[edge_idx])])) {
				query_ans[i] = AnswerInfinity;
			}
			else {
				queries[std::get<1>(edges[edge_idx])].emplace_back(node, i);
			}
		}
		else {
			if (!(tin[std::get<1>(edges[edge_idx])] <= tin[dest] && tout[dest] <= tout[std::get<1>(edges[edge_idx])])) {
				query_ans[i] = AnswerEscaped;
			}
			else if (!fnwk_query(1, tin[std::get<1>(edges[edge_idx])]) && !fnwk_query(tout[std::get<1>(edges[edge_idx])], 2*gs-1)) {
				query_ans[i] = AnswerInfinity;
			}
			else {
				queries[std::get<1>(edges[edge_idx])].emplace_back(node, i);
			}
		}
	}
 
	for (int i = 1; i <= gs; i++) {
		if (is_shop[i]) {
			decomp_add(benis_in,i);
		}
	}
	dfs_solve(1,0);
 
	/*for (int i = 1; i <= gs; i++) {
		std::cout << i << "\n";
		for (const auto& [a, b] : benis_in[i]) {
			std::cout << a << " " << b << "\n";
		}
		std::cout << "\n";
	}*/
 
	for (int i = 0; i < q; i++) {
		if (query_ans[i]==AnswerEscaped) {
			std::cout << "escaped\n";
		}
		else if (query_ans[i]==AnswerInfinity||query_ans[i]>=0x3f3f3f3f3f3f3f3f) {
			std::cout << "oo\n";
		}
		else {
			std::cout << query_ans[i] << "\n";
		}
	}
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...