제출 #791986

#제출 시각아이디문제언어결과실행 시간메모리
791986TranGiaHuy1508Two Currencies (JOI23_currencies)C++17
100 / 100
1573 ms116128 KiB
#include <bits/stdc++.h>
using namespace std;

void main_program();

signed main(){
	ios_base::sync_with_stdio(0); cin.tie(0);
	main_program();
}

#define int long long

using ii = pair<int, int>;

struct Segtree{
	vector<int> tree;
	int _n;

	Segtree() = default;
	Segtree(int N): tree(4*N), _n(N) {}

	int get(int pos) { return get(1, 0, _n - 1, pos); }
	int get(int i, int l, int r, int pos){
		if (l == pos && r == pos) return tree[i];
		int mid = (l + r) >> 1;
		if (pos <= mid) return tree[i] + get(i<<1, l, mid, pos);
		else return tree[i] + get(i<<1|1, mid+1, r, pos);
	}

	void update(int tl, int tr, int delta) { update(1, 0, _n - 1, tl, tr, delta); }
	void update(int i, int l, int r, int tl, int tr, int delta){
		if (tl <= l && r <= tr) tree[i] += delta;
		else if (tl > r || tr < l) return;
		else{
			int mid = (l + r) >> 1;
			update(i<<1, l, mid, tl, tr, delta);
			update(i<<1|1, mid+1, r, tl, tr, delta);
		}
	}
};

template <class T>
struct RMQ{
	vector<vector<T>> table;
	int _n, _lg;

	RMQ() = default;
	RMQ(vector<T> &V){
		_n = V.size();
		_lg = 64 - __builtin_clzll(_n);

		table.assign(_lg, vector<T>(_n));
		table[0] = V;

		for (int j = 1; j < _lg; j++){
			for (int i = 0; i + (1 << j) <= _n; i++){
				table[j][i] = min(table[j-1][i], table[j-1][i + (1 << (j-1))]);
			}
		}
	}

	T get(int l, int r){
		if (l > r) swap(l, r);
		int j = 63 - __builtin_clzll(r - l + 1);
		return min(table[j][l], table[j][r - (1 << j) + 1]);
	}
};

struct Query{
	int a, b;
	int lca;
	int gold, silver;

	int idx;
};

struct PBS{
	int lb, rb;
	vector<Query> qs;
};

int n, m, q;
vector<vector<int>> adj;
vector<ii> edges;
vector<ii> checkpoints;
vector<Query> all_queries;

int timer = 0;
vector<int> tin, tout, occ;
vector<ii> eulertour;
RMQ<ii> rmq;

vector<int> max_silver;

void dfs_euler(int x, int p = -1, int d = 0){
	tin[x] = timer++;
	occ[x] = eulertour.size();
	eulertour.emplace_back(d, x);

	for (auto k: adj[x]){
		if (k == p) continue;
		dfs_euler(k, x, d+1);
		eulertour.emplace_back(d, x);
	}

	tout[x] = timer - 1;
}

inline int LCA(int x, int y){
	return rmq.get(occ[x], occ[y]).second;
}

void main_program(){
	cin >> n >> m >> q;

	adj.resize(n);
	edges.resize(n-1);
	checkpoints.resize(m);
	all_queries.resize(q);

	tin.resize(n);
	tout.resize(n);
	occ.resize(n);
	max_silver.resize(q);

	for (int i = 0; i < n-1; i++){
		int x, y; cin >> x >> y;
		x--; y--;

		adj[x].push_back(y);
		adj[y].push_back(x);

		edges[i] = {x, y};
	}

	for (int i = 0; i < m; i++){
		int P, cost; cin >> P >> cost;
		P--;

		checkpoints[i] = {P, cost};
	}

	sort(checkpoints.begin(), checkpoints.end(), [](ii A, ii B){
		return A.second < B.second;
	});

	dfs_euler(0);
	rmq = RMQ<ii>(eulertour);

	for (int i = 0; i < n-1; i++){
		if (tin[edges[i].first] > tin[edges[i].second])
			swap(edges[i].first, edges[i].second);
	}

	for (int i = 0; i < q; i++){
		int a, b, gold, silver;
		cin >> a >> b >> gold >> silver;
		a--; b--;
		int lca = LCA(a, b);

		all_queries[i] = Query{a, b, lca, gold, silver, i};
	}

	vector<PBS> crrpbs = {PBS{0, m, all_queries}};
	while (!crrpbs.empty()){
		vector<PBS> nxtpbs;
		int prev = -1;
		Segtree st(n);
		Segtree stcnt(n);
		for (auto range: crrpbs){
			if (range.lb == range.rb){
				for (int i = prev + 1; i < range.lb; i++){
					auto [P, cost] = checkpoints[i];
					int x = edges[P].second;
					st.update(tin[x], tout[x], cost);
					stcnt.update(tin[x], tout[x], 1);
				}
				prev = max(prev, range.lb - 1);

				for (auto query: range.qs){
					max_silver[query.idx] =
					stcnt.get(tin[query.a]) + stcnt.get(tin[query.b]) - stcnt.get(tin[query.lca]) * 2;
				}
				continue;
			}

			int mid = (range.lb + range.rb) >> 1;
			for (int i = prev + 1; i <= mid; i++){
				auto [P, cost] = checkpoints[i];
				int x = edges[P].second;
				st.update(tin[x], tout[x], cost);
				stcnt.update(tin[x], tout[x], 1);
			}
			prev = max(prev, mid);

			PBS leftnode{range.lb, mid, {}}, rightnode{mid+1, range.rb, {}};
			for (auto query: range.qs){
				int silver_cost = st.get(tin[query.a]) + st.get(tin[query.b]) - st.get(tin[query.lca]) * 2;
				if (silver_cost <= query.silver) rightnode.qs.push_back(query);
				else leftnode.qs.push_back(query);
			}

			if (!leftnode.qs.empty()) nxtpbs.push_back(leftnode);
			if (!rightnode.qs.empty()) nxtpbs.push_back(rightnode);
		}
		crrpbs.swap(nxtpbs);
	}

	Segtree st(n);
	for (auto pt: checkpoints){
		int x = edges[pt.first].second;
		st.update(tin[x], tout[x], 1);
	}

	for (int i = 0; i < q; i++){
		auto query = all_queries[i];
		int cnt_pt = st.get(tin[query.a]) + st.get(tin[query.b]) - st.get(tin[query.lca]) * 2;
		int gold_cost = cnt_pt - max_silver[i];
		if (gold_cost > query.gold) cout << "-1\n";
		else cout << query.gold - gold_cost << "\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...