A - ふたつの通貨 (Two Currencies) Editorial
by
kaichou243
定数倍の良い重軽分解による実装
重軽分解により実装するとボトルネックとなる並列二分探索パートの計算量が\(O((M+Q) \log M \log^2 N)\)くらいですが、通ります。
#include <bits/stdc++.h>
#define FOR1(a) for (ll _ = 0; _ < ll(a); ++_)
#define FOR2(i, a) for (ll i = 0; i < ll(a); ++i)
#define FOR3(i, a, b) for (ll i = a; i < ll(b); ++i)
#define FOR4(i, a, b, c) for (ll i = a; i < ll(b); i += (c))
#define FOR1_R(a) for (ll i = (a)-1; i >= ll(0); --i)
#define FOR2_R(i, a) for (ll i = (a)-1; i >= ll(0); --i)
#define FOR3_R(i, a, b) for (ll i = (b)-1; i >= ll(a); --i)
#define overload4(a, b, c, d, e, ...) e
#define overload3(a, b, c, d, ...) d
#define FOR(...) overload4(__VA_ARGS__, FOR4, FOR3, FOR2, FOR1)(__VA_ARGS__)
#define FOR_R(...) overload3(__VA_ARGS__, FOR3_R, FOR2_R, FOR1_R)(__VA_ARGS__)
#define sz(c) ((int)(c).size())
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define fi first
#define se second
#define endl "\n"
using namespace std;
using ll=long long;
using P=pair<ll,ll>;
const ll INF=1e18;
const int inf=1e9;
void cincout(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
template<class T,T (*op)(T,T),T (*e)()> struct SegmentTree{
int n;
vector<T> dat;
SegmentTree(int N){
n=1;
while(n<N) n*=2;
dat.assign(n*2,e());
}
void set(int k,T x){
k+=n;
dat[k]=x;
k>>=1;
while(k){
dat[k]=op(dat[k*2],dat[k*2+1]);
k>>=1;
}
}
T query(int l,int r){
l+=n;
r+=n;
T sml=e(),smr=e();
while(l<r){
if(l&1) sml=op(sml,dat[l++]);
if(r&1) smr=op(dat[--r],smr);
l>>=1;
r>>=1;
}
return op(sml,smr);
}
};
ll op(ll a,ll b){ return a+b; }
ll e(){ return 0ll; }
int main(){
cincout();
int n,m,q;
cin>>n>>m>>q;
vector<vector<int>> g(n);
vector<pair<int,int>> edge(n-1);
FOR(i,n-1){
int a,b;
cin>>a>>b;
--a,--b;
g[a].push_back(b);
g[b].push_back(a);
edge[i]={a,b};
}
vector<P> seki(m);
FOR(i,m){
ll p,c;
cin>>p>>c;
--p;
seki[i]={c,p};
}
sort(all(seki));
vector<ll> s(q),t(q),x(q),y(q);
FOR(i,q){
cin>>s[i]>>t[i]>>x[i]>>y[i];
--s[i],--t[i];
}
vector<int> dep(n),siz(n),ver,ind(n),a(n),par(n);
auto cdd=[&](auto rec,int v,int p)->void{
par[v]=p;
siz[v]=1;
for(auto& nv:g[v]){
if(nv==p) continue;
dep[nv]=dep[v]+1;
rec(rec,nv,v);
siz[v]+=siz[nv];
}
};
dep[0]=0;
cdd(cdd,0,-1);
auto hld=[&](auto rec,int v,int p,int k)->void{
ind[v]=ver.size();
ver.push_back(v);
a[v]=k;
if(g[v].size()==1&&v!=0) return;
int mx=0,ind=-1;
FOR(i,g[v].size()){
int nv=g[v][i];
if(nv==p) continue;
if(siz[nv]>mx){
mx=siz[nv];
ind=i;
}
}
rec(rec,g[v][ind],v,k);
FOR(i,g[v].size()){
int nv=g[v][i];
if(nv==p) continue;
if(i!=ind) rec(rec,g[v][i],v,g[v][i]);
}
};
hld(hld,0,-1,0);
auto getpath=[&](int u,int v)->vector<pair<int,int>>{ // [l,r]...
vector<pair<int,int>> ret;
while(a[u]!=a[v]){
if(dep[a[u]]<=dep[a[v]]){
ret.push_back({ind[a[v]],ind[v]});
v=par[a[v]];
}else{
ret.push_back({ind[a[u]],ind[u]});
u=par[a[u]];
}
}
ret.push_back({min(ind[u],ind[v]),max(ind[u],ind[v])});
return ret;
};
FOR(i,n-1){
if(dep[edge[i].first]<dep[edge[i].second]){
swap(edge[i].first,edge[i].second);
}
}
vector<int> ok(q),ng(q,m+1);
FOR(tme,25){
vector<int> mid(q);
FOR(i,q) mid[i]=(ok[i]+ng[i])/2;
vector<vector<int>> mp(m+1);
FOR(i,q) mp[mid[i]].push_back(i);
SegmentTree<ll,op,e> st(n);
FOR(i,1,m+1){
int tmp=edge[seki[i-1].second].first;
st.set(ind[tmp],st.query(ind[tmp],ind[tmp]+1)+seki[i-1].first);
for(auto& j:mp[i]){
auto p=getpath(s[j],t[j]);
ll sum=0;
FOR(k,p.size()-1){
sum+=st.query(p[k].first,p[k].second+1);
}
sum+=st.query(p[sz(p)-1].first+1,p[sz(p)-1].second+1);
if(sum<=y[j]){
ok[j]=mid[j];
}else{
ng[j]=mid[j];
}
}
}
}
vector<ll> ans(q);
vector<vector<int>> mp(m+1);
FOR(i,q) mp[ok[i]].push_back(i);
SegmentTree<ll,op,e> st(n);
FOR(i,m){
int tmp=edge[seki[i].second].first;
st.set(ind[tmp],st.query(ind[tmp],ind[tmp]+1)+1);
}
for(auto& j:mp[0]){
auto p=getpath(s[j],t[j]);
ll sum=0;
FOR(k,p.size()-1) sum+=st.query(p[k].first,p[k].second+1);
sum+=st.query(p[sz(p)-1].first+1,p[sz(p)-1].second+1);
ans[j]=sum;
}
FOR(i,1,m+1){
int tmp=edge[seki[i-1].second].first;
st.set(ind[tmp],st.query(ind[tmp],ind[tmp]+1)-1);
for(auto& j:mp[i]){
auto p=getpath(s[j],t[j]);
ll sum=0;
FOR(k,p.size()-1) sum+=st.query(p[k].first,p[k].second+1);
sum+=st.query(p[sz(p)-1].first+1,p[sz(p)-1].second+1);
ans[j]=sum;
}
}
FOR(i,q){
if(ans[i]<=x[i]) cout<<x[i]-ans[i]<<'\n';
else cout<<-1<<'\n';
}
}
posted:
last update:
