제출 #1369117

#제출 시각아이디문제언어결과실행 시간메모리
1369117marcogambaroTwo Currencies (JOI23_currencies)C++20
100 / 100
1695 ms63196 KiB
#include <bits/stdc++.h>
using namespace std;
mt19937 timmy_loves_gambling(73);
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define readv(v) do { for(auto &i: v) cin >> i; } while(0)
#define _ << " " <<
#define lf "\n"
#define ll long long
#define ull unsigned long long
#define pii pair<int, int>
#define pll pair<long long, long long>
#define fi first
#define se second
template<typename... Args>
using vec = vector<Args...>;
#ifndef MARCO
bool dbg = 0;
#define infor(str, ...)
#define infof(str, ...)
#else
bool dbg = 1;
#define infor(str, ...) do { print(stderr, str, ##__VA_ARGS__); } while(0)
#define infof(str, ...) do { println(stderr, str, ##__VA_ARGS__); } while(0)
#endif

constexpr int LOG = 20;

int N, M, Q;
vec<int> tin, tout, depth;
vec<vec<int>> tb;
vector<vec<int>> G;
vec<int> par;
vec<pii> ed;

int highest(int a, int b) {
	if(depth[a] < depth[b]) return a;
	return b;
}

void dfs(int v, int p, int d) {
	par[v] = p;
	depth[v] = d;
	static int t = 0;
	tb[0][t] = v;
	tin[v] = t++;
	for(auto &u: G[v]) {
		if(u == p) continue;
		dfs(u, v, d+1);
		tb[0][t++] = v;
	}
	tout[v] = t;
}

void construct() {
	for(int i=1; i<LOG; i++) {
		int pw = (1 << i);
		for(int l=0; l+pw <= 2*N; l++)
			tb[i][l] = highest(tb[i-1][l], tb[i-1][l + pw/2]);
	}
}

int get_lca(int l, int r) {
	l = tin[l], r = tin[r];
	if(l > r) swap(l, r);
	r++;

	int s = 31 - __builtin_clz(r - l);
	int pw = (1 << s);
	return highest(tb[s][l], tb[s][r-pw]);
}

struct segtree {
	vector<ll> t, lazy;

	segtree() {
		t.resize(N*8);
		lazy.resize(N*8);
	}

	void push(int v) {
		for(int u = v*2; u < v*2+2; u++) {
			t[u] += lazy[v];
			lazy[u] += lazy[v];
		}
		lazy[v] = 0;
	}

	void add(int v, int l, int r, int ql, ll qr, ll x) {
		if(qr <= l || r <= ql) return;
		if(ql <= l && r <= qr) {
			t[v] += x;
			lazy[v] += x;
			return;
		}
		push(v);
		int m = (l+r)/2;
		add(v*2, l, m, ql, qr, x);
		add(v*2+1, m, r, ql, qr, x);
	}
	void add(int v, ll x) {
		add(1, 0, N*2, tin[v], tout[v], x);
	}

	ll get(int v, int l, int r, int q) {
		if(r-l == 1) return t[v];
		push(v);
		int m = (l+r)/2;
		if(q < m) return get(v*2, l, m, q);
		return get(v*2+1, m, r, q);
	}
	ll get(int v) {
		return get(1, 0, N*2, tin[v]);
	}

	ll query(int a, int b, int lca) {
		return get(a) + get(b) - 2*get(lca);
	}
};

signed main(){	
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);   
    
	cin >> N >> M >> Q;

	G.resize(N);
	tin.resize(N);
	tout.resize(N);
	depth.resize(N);
	ed.resize(N-1);
	par.resize(N);
	tb = vector(LOG, vector<int>(2*N));

	for(int i=0; i<N-1; i++) {
		int a, b; cin >> a >> b;
		a--, b--;
		G[a].push_back(b);
		G[b].push_back(a);
		ed[i] = {a, b};
	}

	dfs(0, -1, 0);
	construct();

	segtree silver, gold;

	vec<pll> cost(M); // [silver coins, node]
	for(int i=0; i<M; i++) {
		int e, c; cin >> e >> c;
		e--;
		auto [a, b] = ed[e];

		if(par[b] == a) swap(a, b);
		cost[i] = {c, a};
		gold.add(a, 1);
	}
	sort(all(cost));

	vec<pii> Qs(Q);
	vec<ll> Qgold(Q), Qsilver(Q);
	vec<ll> ans(Q); // minimum gold needed

	for(int i=0; i<Q; i++) {
		cin >> Qs[i].fi >> Qs[i].se >> Qgold[i] >> Qsilver[i];
		Qs[i].fi--, Qs[i].se--;
		ans[i] = gold.query(Qs[i].fi, Qs[i].se, get_lca(Qs[i].fi, Qs[i].se));
	}


	int s = 0;

	auto conquer = [&](int l, int r, vector<int> &id, auto &&conquer) -> void {
		if(id.empty()) return;
		int m = (l+r)/2;
		infof("conquering l = {} r = {} m = {}", l, r, m);

		while(s < m) {
			silver.add(cost[s].se, cost[s].fi);
			gold.add(cost[s].se, -1);
			s++;
		}
		while(s > m) {
			s--;
			silver.add(cost[s].se, -cost[s].fi);
			gold.add(cost[s].se, +1);
		}

		vec<int> L, R;

		for(auto &i: id) {
			auto &[a, b] = Qs[i];
			int lca = get_lca(a, b);

			ll ks = silver.query(a, b, lca);
			ll kg = gold.query(a, b, lca);

			if(ks <= Qsilver[i]) {
				ans[i] = min(ans[i], kg);
				R.push_back(i);
			}
			else {
				L.push_back(i);
			}
		}

		if(r-l == 1) return;

		conquer(l, m, L, conquer);
		conquer(m, r, R, conquer);
	};

	vec<int> id(Q);
	iota(all(id), 0);
	conquer(0, M+1, id, conquer);

	for(int i = 0; i < Q; i++) {
		cout << max(-1LL, Qgold[i] - ans[i]) << lf;
	}
}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…