二分枚举答案,判定答案是否合法
贪心:每一个叶子只能经过一遍,因此叶子的顺序一定是一个dfs序,即走完一棵子树中的所有叶子才会到子树外
根据这个贪心可以dp,设$f[k][l][r]$表示仅考虑$k$的子树,$l$和$r$为第一个和最后一个叶子到根的距离,时间复杂度大约有$o(n^{4或5})$,无法通过
考虑优化,将所有$f[k][l][r]=1$的$(l,r)$记录下来,若存在$l'le l$且$r'le r$,$(l,r)$一定没有意义,这可以用一个单调栈来维护,那么同一个$l/r$所对应的$r/l$最多只有1个
转移考虑合并,不妨假设左子树比右子树小,枚举左子树中的$(l_{1},r_{1})$,对于右子树中的$(l_{2},r_{2})$,有两种转移的可能:1.若$r_{1}+l_{2}+v_{ls}+v_{rs}le ans$,转移到$(l_{1}+v_{ls},r_{2}+v_{rs})$;2.若$l_{1}+r_{2}+v_{ls}+v_{rs}le ans$,转移到$(l_{2}+v_{rs},r_{1}+v_{ls})$
可以利用单调性来优化,即找到满足$l_{2}le ans-r_{1}-v_{ls}-v_{rs}$且$r_{2}$最小的位置(第一种转移),那么每一组$(l_{1},r_{1})$最多转移到$k$中的两个状态(反之同理),即有$|state[k]|le 2min(|state[ls]|,|state[rs]|)$,空间复杂度为$o(nlog_{2}n)$,时间复杂度即为空间复杂度乘上二分,为$o(nlog^{ 2}_{2}n)$

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define ll long long 5 #define fi first 6 #define se second 7 vector<pair<ll,ll> >v,f[N]; 8 int n,x,ls[N],rs[N],w[N]; 9 ll ans; 10 void dfs(int k){ 11 f[k].clear(); 12 if ((!ls[k])&&(!rs[k])){ 13 f[k].push_back(make_pair(0,0)); 14 return; 15 } 16 dfs(ls[k]); 17 dfs(rs[k]); 18 ll s=ans-w[ls[k]]-w[rs[k]]; 19 for(int i=0,j=0;i<f[ls[k]].size();i++){ 20 while ((j<f[rs[k]].size())&&(f[rs[k]][j].fi<=s-f[ls[k]][i].se))j++; 21 if ((j)&&(f[rs[k]][j-1].fi<=s-f[ls[k]][i].se))f[k].push_back(make_pair(f[ls[k]][i].fi+w[ls[k]],f[rs[k]][j-1].se+w[rs[k]])); 22 } 23 swap(ls[k],rs[k]); 24 for(int i=0,j=0;i<f[ls[k]].size();i++){ 25 while ((j<f[rs[k]].size())&&(f[rs[k]][j].fi<=s-f[ls[k]][i].se))j++; 26 if ((j)&&(f[rs[k]][j-1].fi<=s-f[ls[k]][i].se))f[k].push_back(make_pair(f[ls[k]][i].fi+w[ls[k]],f[rs[k]][j-1].se+w[rs[k]])); 27 } 28 if (!f[k].size())return; 29 sort(f[k].begin(),f[k].end()); 30 v.clear(); 31 v.push_back(f[k][0]); 32 for(int i=1;i<f[k].size();i++) 33 if (f[k][i].se<v[(int)v.size()-1].se)v.push_back(f[k][i]); 34 f[k]=v; 35 } 36 bool pd(ll k){ 37 ans=k; 38 dfs(1); 39 return f[1].size(); 40 } 41 int main(){ 42 scanf("%d",&n); 43 for(int i=2;i<=n;i++){ 44 scanf("%d%d",&x,&w[i]); 45 if (!ls[x])ls[x]=i; 46 else rs[x]=i; 47 } 48 ll l=0,r=1LL*N*N; 49 while (l<r){ 50 ll mid=(l+r>>1); 51 if (pd(mid))r=mid; 52 else l=mid+1; 53 } 54 printf("%lld",l); 55 }