【题解】P9128 [USACO23FEB] Fertilizing Pastures G
零:前言
下位紫难度吧
壹:T=0
此时时间为 \(2*(n-1)\)
花费的话,我们贪心重排兄弟节点,然后dp处理
对于兄弟节点 \(u,v\)
先遍历 \(u\) 子树再遍历 \(v\) 子树,此时贡献为 \(E(u)+E(v)+siz(u)*sumA(v)\)
先遍历 \(v\) 子树再遍历 \(u\) 子树,此时贡献为 \(E(u)+E(v)+siz(v)*sumA(u)\)
取最小值,即 \(u<v,siz(u)*sumA(v)<=siz(v)*sumA(u)\) 得 \(u<v,siz(u)/sumA(u)<=siz(v)/sumA(v)\)
排序即可
然后 \(F\) 数组dp转移
贰:T=1
此时时间为 \(2*(n-1)-maxdep\)
对于花费,我们可以开一个 \(G\) 数组,每次把所有 \(=maxdep\) 的分别移到最右边,统计 \(G\) 最小值
当前节点 \(u\) ,儿子节点 \(v\)
\(suf\) 表示排序完毕时 \(v\) 后面的兄弟节点的 \(sumA\) 的和, \(len\) 表 \(siz\) 的和
\(G_u=min\{F_u-F_v-suf*siz_v*2+G_v+len*2*sumA_v\}\)
参:代码
#include<bits/stdc++.h>
#define inf 5e18
#define int long long
using namespace std;
const int N=2e5+10;
vector<int> mp[N];
int a[N];
int siz[N],sumA[N];
int dep[N],maxdep[N];
int fa[N];
void dfs1(int u,int pa){
siz[u]=1;
sumA[u]=a[u];
fa[u]=pa;
maxdep[u]=dep[u]=dep[pa]+1;
for(auto v:mp[u]){
dfs1(v,u);
siz[u]+=siz[v];
sumA[u]+=sumA[v];
maxdep[u]=max(maxdep[u],maxdep[v]);
}
}
int F[N],G[N];
bool cmp(int a,int b){
return 1.0*siz[a]/sumA[a]<1.0*siz[b]/sumA[b];
}
void dfs2(int u){
sort(mp[u].begin(),mp[u].end(),cmp);
int s=0;
for(auto v:mp[u]){
dfs2(v);
F[u]+=F[v]+(s+1)*sumA[v];
s+=2*siz[v];
}
}
void dfs3(int u){
if(mp[u].size()) G[u]=inf;
else G[u]=0;
reverse(mp[u].begin(),mp[u].end());
int len=0,suf=0;
for(auto v:mp[u]){
dfs3(v);
if(maxdep[u]==maxdep[v]) G[u]=min(G[u],F[u]-F[v]+G[v]-suf*siz[v]*2+len*2*sumA[v]);
suf+=sumA[v];
len+=siz[v];
}
//cerr<<"-->"<<u<<" "<<G[u]<<"\n";
}
signed main(){
int n,T;cin>>n>>T;
for(int i=2;i<=n;i++){
int f;cin>>f>>a[i];
mp[f].push_back(i);
}
dfs1(1,0);
dfs2(1);
dfs3(1);
if(T==0) cout<<2*(n-1)<<" "<<F[1]<<"\n";
else cout<<2*(n-1)-maxdep[1]+1<<" "<<G[1]<<"\n";
return 0;
}

浙公网安备 33010602011771号