P12491 题解
DaiRuiChen007 · · 题解
Problem Link
题目大意
给定一棵树,每个点有两个权值
a_i,b_i 。对于树上的一条简单路径,若这条路径上b 之和乘上a 的最小值大于等于一个常数V ,那么这条路径被称作一条好的路径,求所有好的路径中,\sum b 的最小值。数据范围:
n\le 2\times 10^5 。
思路分析
点分治变成
那么按
时间复杂度
代码呈现
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=2e5+5;
const ll inf=2e18;
struct info {
ll v1,v2;
int c1,c2;
inline friend info operator +(info u,info v) {
if(u.v1>v.v1) swap(u,v);
if(v.c1==u.c1) {
if(v.v2<u.v2) u.v2=v.v2,u.c2=v.c2;
} else if(v.v1<u.v2) u.v2=v.v1,u.c2=v.c1;
return u;
}
} tr[MAXN],I={inf,inf,0,0};
int n,tp,siz[MAXN],cur[MAXN];
ll V,a[MAXN],b[MAXN],ans=inf;
vector <int> G[MAXN];
bool vis[MAXN];
ll st[MAXN];
void solve(int u) {
if(a[u]*b[u]>=V) ans=min(ans,b[u]);
vector <array<ll,3>> Q;
for(int v:G[u]) if(!vis[v]) {
function<void(int,int,ll,ll)> dfs3=[&](int x,int fz,ll mn,ll su) {
mn=min(mn,a[x]),su+=b[x],Q.push_back({mn,su,v}),siz[x]=1;
for(int y:G[x]) if(!vis[y]&&y!=fz) dfs3(y,x,mn,su),siz[x]+=siz[y];
};
dfs3(v,u,a[u],b[u]);
}
tp=0,sort(Q.begin(),Q.end(),greater<>());
for(auto i:Q) st[++tp]=i[1];
sort(st+1,st+tp+1),tp=unique(st+1,st+tp+1)-st-1;
fill(tr,tr+tp+1,I);
auto add=[&](int x,info v) { for(;x;x&=x-1) tr[x]=tr[x]+v; };
auto qry=[&](int x) { info s=I; for(;x<=tp;x+=x&-x) s=s+tr[x]; return s; };
for(auto i:Q) {
if(i[1]>=(V+i[0]-1)/i[0]) ans=min(ans,i[1]);
int id=lower_bound(st+1,st+tp+1,(V+i[0]-1)/i[0]-i[1]+b[u])-st;
info z=qry(id);
ans=min(ans,i[1]+(z.c1==i[2]?z.v2:z.v1)-b[u]);
id=lower_bound(st+1,st+tp+1,i[1])-st;
add(id,{i[1],inf,(int)i[2],0});
}
}
void dfs1(int u) {
solve(u),vis[u]=true;
for(int v:G[u]) if(!vis[v]) {
int rt=0;
function<void(int,int)> dfs2=[&](int x,int fz) {
cur[x]=siz[v]-siz[x];
for(int y:G[x]) if(y!=fz&&!vis[y]) dfs2(y,x),cur[x]=max(cur[x],siz[y]);
if(!rt||cur[x]<cur[rt]) rt=x;
};
dfs2(v,u),dfs1(rt);
}
}
signed main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>V;
for(int i=1;i<=n;++i) cin>>a[i]>>b[i];
for(int i=1,u,v;i<n;++i) cin>>u>>v,G[u].push_back(v),G[v].push_back(u);
dfs1(1),cout<<ans<<"\n";
return 0;
}