Submission #1047495

#TimeUsernameProblemLanguageResultExecution timeMemory
1047495ymmTwo Currencies (JOI23_currencies)C++17
100 / 100
1750 ms555968 KiB
#include <bits/stdc++.h>
#define Loop(x,l,r) for (ll x = (l); x < (ll)(r); ++x)
#define LoopR(x,l,r) for (ll x = (r)-1; x >= (ll)(l); --x)
typedef long long ll;
typedef std::pair<int, int> pii;
typedef std::pair<ll , ll > pll;
using namespace std;

pll operator+(const pll &a, const pll &b) {
	return { a.first + b.first, a.second + b.second };
}

class Seg {
private:
	struct Node {
		Node *l, *r;
		pll val;

		int cl, cr;
		pll cv;

		static Node *nw() {
			static Node pool[(1<<29)/sizeof(Node)];
			static int p = 0;
			return &pool[p++];
		}
	};
	vector<Node *> roots = {0};
	vector<ll> tags;
	int begin, end;

	pll get(Node *t, int l, int r, int b, int e) {
		if (r <= b || e <= l || !t)
			return {};
		if (l <= b && e <= r)
			return t->val;
		if (l == t->cl && r == t->cr)
			return t->cv;
		t->cl = l;
		t->cr = r;
		return t->cv = get(t->l, l, r, b, (b+e)/2) + get(t->r, l, r, (b+e)/2, e);
	}

	Node *add(Node *t, int p, const pll &x, int b, int e) {
		Node *ans = Node::nw();
		ans->val = t? t->val + x: x;
		if (e - b > 1) {
			if (p < (b + e)/2) {
				ans->l = add(t? t->l: 0, p, x, b, (b+e)/2);
				ans->r = t? t->r: 0;
			} else {
				ans->l = t? t->l: 0;
				ans->r = add(t? t->r: 0, p, x, (b+e)/2, e);
			}
		}
		return ans;
	}

public:
	Seg(int l, int r) : begin(l), end(r) {}

	void add(int p, const pll &x, ll tag) {
		roots.push_back(add(roots.back(), p, x, begin, end));
		tags.push_back(tag);
	}

	pll get_lower_bound(int l, int r, ll tag) {
		int p = lower_bound(tags.begin(), tags.end(), tag) - tags.begin();
		return get(roots[p], l, r, begin, end);
	}
};

const int N = 100'010;

struct Node {
	vector<Node *> adj;
	Node *par;
	Node *hroot, *hleaf, *hchild;
	Seg *hseg;
	int h;
	int sz;
} graph[N];

ostream &operator<<(ostream &o, Node *v) {
	o << "N";
	if (v)
		o << v - graph;
	else
		o << "(nil)";
	return o;
}

void dfs1(Node *v, Node *p, int h)
{
	v->sz = 1;
	v->h = h;
	v->par = p;
	for (auto u : v->adj) {
		if (u == p)
			continue;
		dfs1(u, v, h + 1);
		if (!v->hchild || v->hchild->sz < u->sz)
			v->hchild = u;
	}
}

void dfs2(Node *v, Node *hroot)
{
	hroot->hleaf = v;
	v->hroot = hroot;
	for (auto u : v->adj) {
		if (u == v->par)
			continue;
		dfs2(u, v->hchild == u? hroot: u);
	}
	if (hroot == v)
		v->hseg = new Seg(v->h, v->hleaf->h + 1);
}

Node *lower(Node *v, Node *u) {
	return v->h > u->h? v: u;
}

void add_checkpoint(Node *v, pll x, ll tag)
{
	v->hroot->hseg->add(v->h, x, tag);
}

class QueryCache : public vector<tuple<Seg *, int, int>> {
public:
	pll query(ll tag) {
		pll sum = {};
		for (auto [s, l, r] : *this)
			sum = sum + s->get_lower_bound(l, r, tag);
		return sum;
	}
};

QueryCache get_seg_ranges(Node *v, Node *u)
{
	QueryCache ans;
	while (v->hroot != u->hroot) {
		if (v->hroot->h < u->hroot->h)
			swap(v, u);
		ans.emplace_back(v->hroot->hseg, v->hroot->h, v->h + 1);
		v = v->hroot->par;
	}
	if (v->h < u->h)
		swap(v, u);
	ans.emplace_back(v->hroot->hseg, u->h + 1, v->h + 1);
	return ans;
}

vector<pair<Node *, Node *>> edges;
struct Checkpoint {
	Node *v, *u;
	ll s;

	bool operator<(const Checkpoint &other) { return s < other.s; };
};
vector<Checkpoint> checkpoints;
const ll inf = 1.01e18;

ll solve(Node *v, Node *u, ll gold, ll silver)
{
	int l = 0, r = checkpoints.size();
	QueryCache qc = get_seg_ranges(v, u);
	while (l < r) {
		int m = (l + r + 1)/2;
		if (qc.query(m).first > silver)
			r = m-1;
		else
			l = m;
	}
	ll ans = gold - (qc.query(checkpoints.size()).second - qc.query(l).second);
	if (ans < 0)
		ans = -1;
	return ans;
}

void make_hls()
{
	dfs1(graph, 0, 0);
	dfs2(graph, graph);
	sort(checkpoints.begin(), checkpoints.end());
	Loop (i,0,checkpoints.size()) {
		auto &c = checkpoints[i];
		add_checkpoint(lower(c.v, c.u), {c.s, 1}, i);
	}
}

Node *read_node() { int i; cin >> i; return graph + i - 1; }

int main()
{
	cin.tie(0) -> sync_with_stdio(false);
	int n, m, q;
	cin >> n >> m >> q;
	Loop (i,0,n-1) {
		auto v = read_node();
		auto u = read_node();
		edges.emplace_back(v, u);
		v->adj.push_back(u);
		u->adj.push_back(v);
	}
	Loop (i,0,m) {
		int p;
		ll s;
		cin >> p >> s;
		checkpoints.push_back((Checkpoint){
				.v = edges[p-1].first,
				.u = edges[p-1].second,
				.s = s,
		});
	}
	make_hls();
	while (q--) {
		auto v = read_node();
		auto u = read_node();
		ll gold, silver;
		cin >> gold >> silver;
		cout << solve(v, u, gold, silver) << '\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...