제출 #1336092

#제출 시각아이디문제언어결과실행 시간메모리
1336092NAMINTwo Currencies (JOI23_currencies)C++20
10 / 100
5095 ms45872 KiB
#include <bits/stdc++.h>
#define ll long long
#define endl "\n"
using namespace std;

struct STsum{
	int len=1;
	vector<ll> tree;

	STsum(int l){
		while(len<l){
			len*=2;
		}
		tree=vector<ll>(2*len,0);
	}

	void update(int idx,ll v){
		idx+=len;
		tree[idx]+=v;
		for(idx/=2;idx>=1;idx/=2)
			tree[idx]=tree[idx*2]+tree[idx*2+1];
	}

	ll query(int l,int r){
		ll res=0;
		l+=len,r+=len;
		while(l<=r){
			if(l%2==1)
				res += tree[l++];
			if(r%2==0)
				res += tree[r--];
			l/=2,r/=2;
		}
		return res;
	}
};

const int LOG = 20;
const int mxN = 100001;
int N,M,Q;
vector<int> adj[mxN];
vector<pair<int,int>> edges;
vector<int> depth(mxN,0);
vector<int> sub_sz(mxN,1);
vector<int> in(mxN,0);
vector<int> ot(mxN,0);
vector<int> parent(mxN,-1);
int jump[mxN][LOG];

int timer;
void dfs(int node,int p=-1){
	parent[node]=p;
	in[node]=timer++;
	for(int u : adj[node]){
		if(u==p)
			continue;
		depth[u]=depth[node]+1;
		dfs(u,node);
		sub_sz[node]+=sub_sz[u];
	}
	ot[node]=timer++;
}

ll get_sum(int node,int parent,STsum &seg){
	return seg.query(0,in[node])-seg.query(0,in[parent]);
}

void activate(int node,ll v,STsum &seg){
	seg.update(in[node],v);
	seg.update(ot[node],-v);
}

void init_lca(){
	for(int i=0;i<mxN;i++){
		for(int e=0;e<LOG;e++){
			jump[i][e]=-1;
		}
	}
	for(int u=0;u<mxN;u++){
		jump[u][0]=parent[u];
	}
	
	for(int e=1;e<LOG;e++){
		for(int u=0;u<mxN;u++){
			if(jump[u][e-1]!=-1)
				jump[u][e]=jump[jump[u][e-1]][e-1];
		}
	}
}

int lca(int a,int b){
	if(depth[a]<depth[b])
		swap(a,b);
	int k = depth[a]-depth[b];
	for(int e=LOG-1;e>=0;e--){
		if((1<<e)&k){
			a=jump[a][e];
		}
	}

	if(a==b)
		return a;
	
	for(int e=LOG-1;e>=0;e--){
		int u = jump[a][e],v = jump[b][e];
		if(u!=v){
			a=u,b=v;
		}
	}
	return parent[a];
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	timer=0;

	cin >> N >> M >> Q;
	for(int i=0;i<N-1;i++){
		int u,v;
		cin >> u >> v;
		u--,v--;
		adj[u].push_back(v);
		adj[v].push_back(u);
		edges.push_back(make_pair(u,v));
	}
	dfs(0);
	for(int i=0;i<N-1;i++){
		int u=edges[i].first,v=edges[i].second;
		if(depth[u]>depth[v])
			swap(edges[i].first,edges[i].second);
	}
	
	vector<pair<ll,int>> op;//cost,node
	vector<int> nbop(N,0);
	for(int i=0;i<M;i++){
		ll idx_arr,cost;
		cin >> idx_arr >> cost;
		idx_arr--;
		op.push_back(make_pair(cost,edges[idx_arr].second));
	}
	sort(op.begin(),op.end());

	vector<ll> s(Q),e(Q),gold(Q),silver(Q);
	for(int i =0;i<Q;i++){
		cin >> s[i] >> e[i] >> gold[i] >> silver[i];
		s[i]--,e[i]--;
	}
	init_lca();
	vector<int> lo(Q,0);
	vector<int> hi(Q,M);

	for(int _=0;_<100;_++){
		STsum seg_act(3*N+1);
		vector<pair<int,int>> mid;
		for(int q=0;q<Q;q++){
			mid.push_back(make_pair(lo[q]+(hi[q]-lo[q]+1)/2,q));
		}
		sort(mid.rbegin(),mid.rend());
		
		for(int k=0;k<=M;k++){//k:=nb activé
			if(k>0)
				activate(op[k-1].second,op[k-1].first,seg_act);
			while(mid.size()>0&&mid.back().first==k){
				int q = mid.back().second;
				int u = s[q],v = e[q];
				if(depth[u]>depth[v])
					swap(u,v);
				int z = lca(u,v);
				ll cost = get_sum(v,z,seg_act);
				if(z!=u)//different path
					cost+=get_sum(u,z,seg_act);

				if(cost<=silver[q])
					lo[q]=k;
				else
					hi[q]=k;
				mid.pop_back();
			}
		}
	}

	vector<pair<int,int>> k_mx;
	for(int q=0;q<Q;q++){
		k_mx.push_back(make_pair(lo[q],q));
	}
	sort(k_mx.rbegin(),k_mx.rend());
	
	vector<ll> ans(Q,-1);
	STsum seg_cnt(3*N+1);
	for(int i=0;i<M;i++){
		activate(op[i].second,1,seg_cnt);
	}
	STsum seg_curcnt(3*N+1);
	
	for(int k=0;k<=M;k++){
		if(k>0){
			activate(op[k-1].second,1,seg_curcnt);
			//cout << op[k-1].second+1 << " : activate"<<endl;
		}
		//cout << "k :" << k << endl;
		while(k_mx.size()>0&&k_mx.back().first==k){
			int q = k_mx.back().second;
			int u = s[q],v = e[q];
			if(depth[u]>depth[v])
				swap(u,v);
			int z = lca(u,v);
			ll C = get_sum(v,z,seg_cnt);
			//cout << "first path :"<<u << ' ' << z << endl;
			if(z!=u)//different path
				C+=get_sum(u,z,seg_cnt);

			ll curC = get_sum(v,z,seg_curcnt);
			//cout << "first path :"<<u << ' ' << z << endl;
			if(z!=u)//different path
				curC+=get_sum(u,z,seg_curcnt);
			//cout << "q and c :" << q << ' ' << C << endl;
			if(gold[q]-(C-curC)>=0)
				ans[q]=gold[q]-(C-curC);
			k_mx.pop_back();
		}
	}

	for(int i=0;i<Q;i++){
		cout << ans[i] << endl;
	}
}


#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...