Submission #1222702

#TimeUsernameProblemLanguageResultExecution timeMemory
1222702ByeWorldTwo Currencies (JOI23_currencies)C++20
100 / 100
1398 ms89004 KiB
#include <bits/stdc++.h>
// #pragma GCC optimize("O3")
#define int long long
#define ll long long
#define se second
#define fi first
#define pb push_back
#define lf (id<<1)
#define rg ((id<<1)|1)
#define md ((l+r)>>1)
using namespace std;
typedef pair<int,int> pii;
typedef pair<pii,pii> ipii;
const int MAXN = 1e5+10;
const int SQRT = 450;
const int INF = 2e9;
const int MOD = 998244353;
const int LOG = 20;
int sum(int a, int b){ a%=MOD; b%=MOD; return (a+MOD+b)%MOD; }
void chsum(int &a, int b){ a%=MOD; b%=MOD; a = (a+MOD+b)%MOD; }
int mul(int a, int b){ return (a*b)%MOD; }
int expo(int a, int b){
	if(b==0) return 1;
	int te = expo(a, b/2); te = mul(te,te);
	return (b%2 ? mul(te,a) : te);
}
void chmul(int &a, int b){ a = (a*b)%MOD; }
void chmn(auto &a, auto b){ a = min(a, b); }
void chmx(auto &a, auto b){ a = max(a, b); }

int n, m, q;
int ans[MAXN], u[MAXN], v[MAXN];
int idx[MAXN], co[MAXN], s[MAXN], t[MAXN], x[MAXN], y[MAXN];

struct fen {
	pii st[MAXN];
	void bd(){
		for(int i=0; i<=MAXN-10; i++) st[i] = {0, 0};
	}
	pii que(int x){
		pii te = {0, 0};
		for(; x; x-=x&-x) te.fi += st[x].fi, te.se += st[x].se;
		return te;
	}
	void upd(int x, pii p){
		for(; x<=MAXN-10; x+=x&-x) st[x].fi += p.fi, st[x].se += p.se;
	}
} A;

vector<array<int,3>> cek[MAXN];
int cnt[MAXN][4], point[MAXN];
int pr[MAXN];

vector<int> adj[MAXN], tree[MAXN];
int sub[MAXN], root[MAXN], dep[MAXN], par[MAXN], tim[MAXN], day;
void trav(int nw, int pa){
	for(auto nx : tree[nw]){
		if(nx==pa) continue;
		adj[nw].pb(nx);
		trav(nx,nw);
	}
}
void dfs(int nw, int pa){
	sub[nw] = 1; dep[nw] = dep[pa]+1; par[nw] = pa;

	for(auto nx : adj[nw]){
		dfs(nx, nw); sub[nw] += sub[nx];
	}
}
void bd(int nw, int roo){
	tim[nw] = ++day;
	root[nw] = roo;
	if(adj[nw].empty()) return;
	bd(adj[nw][0], roo);

	for(int i=1; i<adj[nw].size(); i++)
		bd(adj[nw][i], adj[nw][i]);
}
pii GET(int x, int y){
	if(x < y) assert(false);
	pii t1 = A.que(x), t2 = A.que(y);
	pii ret = pii(t1.fi-t2.fi, t1.se-t2.se);
	return ret;
}
pii hld(int x, int y){
	pii tot = {0, 0};
	while(root[x] != root[y]){
		if(dep[root[x]] > dep[root[y]]) swap(x, y);
		// gerak y ke root
		// mau dpt node y ke root[y]
		pii que = GET(tim[y], tim[root[y]]-1); // bawah ke atas

		// cout << y << ' ' << root[y] << ' ' << que.fi<<' '<<que.se<<" root\n";
		tot.fi += que.fi; tot.se += que.se;
		y = par[root[y]];
	}
	if(dep[x] > dep[y]) swap(x, y);
	if(x != y){
		// dr node y ke bawahnya x
		// cout << tim[y] <<' '<<tim[x] << " tim\n";
		pii que = GET(tim[y], tim[x]); // bawah ke atas
		tot.fi += que.fi; tot.se += que.se;
		// cout << y << ' ' << x << ' ' << que.fi << ' '<< que.se << " terakhir\n";
	}
	return tot;
}
signed main(){
	ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n>>m>>q;
	for(int i=1; i<=n-1; i++){
		cin>>u[i]>>v[i]; 
		tree[u[i]].pb(v[i]); tree[v[i]].pb(u[i]);
	}
	trav(1, 0);
	dfs(1, 0);
	for(int i=1; i<=n; i++){
		if(adj[i].empty()) continue;
		for(int j=1; j<adj[i].size(); j++)
			if(sub[ adj[i][0] ] < sub[ adj[i][j] ])
				swap(adj[i][0], adj[i][j]);
	}
	bd(1, 1);
	for(int i=1; i<=n-1; i++){
		if(dep[ u[i] ] > dep[ v[i] ]) swap(u[i], v[i]);
	}

	vector<int> cc; cc.pb(-1);
	for(int i=1; i<=m; i++){
		cin>>idx[i]>>co[i];
		cc.pb(co[i]);
	}
	sort(cc.begin(), cc.end()); 
	cc.resize(unique(cc.begin(), cc.end())-cc.begin());
	int siz = cc.size()-1;

	vector<pii> edge; edge.pb({-1,-1});
	for(int i=1; i<=m; i++){
		co[i] = lower_bound(cc.begin(), cc.end(), co[i])-cc.begin(); 
		edge.pb({co[i], idx[i]});
	}
	sort(edge.begin(), edge.end());

	for(int i=1; i<=q; i++){
		cin>>s[i]>>t[i]>>x[i]>>y[i];

		cek[(siz+1)/2].pb({1, siz, i});
	}
	
	// build point
	for(int i=1; i<=m; i++){
		int id = edge[i].se; // idx dr edge
		id = v[id]; // idx dr node
		int cost = cc[ edge[i].fi ];
		// cout << id << ' ' << cost << " cost\n";
		A.upd(tim[id], pii(cost, 1) );
	}
	// cout << GET(tim[6], tim[1]).se << " edge\n";
	// cout << "here\n";
	for(int i=1; i<=q; i++){
		int up = s[i], dw = t[i];
		// cout << up << ' ' << dw << " up\n";
		pii ret = hld(up, dw);

		point[i] = ret.se; // lewat brp edge
		// cout << i << ' ' << point[i] << " pp\n\n";
	}
	bool done = 0;
	while(!done){
		done = 1; A.bd();

		int edupd = 1; // edge ter yg blm update
		for(int i=1; i<=siz; i++){
			// masukin yg costnya = cc[i], cost of unique edge
			while(edupd<edge.size() && edge[edupd].fi == i){
				int id = edge[edupd].se; // idx dr edge
				id = v[id];
				A.upd(tim[id], pii(cc[i], 1) );
				edupd++;
			}
			// cout << "masulk\n";
			// solve cek(i)
			for(auto pp : cek[i]){
				auto [l, r, qidx] = pp;
				int silv = y[qidx];

				int up = s[qidx], dw = t[qidx];
				pii ret = hld(up, dw);
				// silver, num edge

				if(ret.fi <= silv){ // oh bisa 
					cnt[qidx][0] = i; cnt[qidx][1] = ret.fi; 
					cnt[qidx][2] = ret.se;

					int mid = (i+1+r)>>1;
					if(i+1<=r){
						cek[mid].pb({i+1, r, qidx}); done = 0;
					}

				} else {
					int mid = (l+i-1)>>1;
					if(l<=i-1){
						cek[mid].pb({l, i-1, qidx}); done = 0;
					}
				}
			}

			cek[i].clear();
		}
	}
	// cout << siz << " unique cost\n";
	for(int i=1; i<=q; i++){ // punya y[i]
		// cout << i << " i\n";
		// cout << cnt[i][0] << ' '<< cnt[i][1] << ' ' << cnt[i][2] << " cnt\n\n";
		int ed = cnt[i][2];
		if(cnt[i][0]+1 <= siz){
			int sis = y[i]-cnt[i][1];
			ed += sis/cc[ cnt[i][0]+1 ]; // bisa ambil segini lagi
		}

		int gold = point[i]-ed;

		cout << (gold > x[i] ? -1 : x[i]-gold) << '\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...