题解:P17019 [ROI 2026 Day1] 泰莫利亚的调查
833B 的同学那里得到的排序除外线性且不需要复杂 dp 的做法。
问题转化为选择
考虑弱化版:
::::info[弱化版]
贪心,先选最长链,将这个链的所有边长变为
:::info[贪心证明] 反证。如果不选最长链,考虑选的链中,有一条链和最长链交集最长,将这条链替换为最长链更优秀。 :::
| 注意到上面的东西就是将树长链剖分后选最长的 |
|---|
若存在蓝色节点在选的链中,
考虑改变一下树的形态转化为弱化版。类似网络流的思想,考虑最大值的本质为,对于所有数覆盖比它小的数,而选的链就是覆盖点的所有祖先。进而考虑如下建模。
不用真的建出来这个树,按照这个模型直接在原来的树上做即可。
:::success[code] 不卡常的题好好好好好评。
#include<bits/stdc++.h>
#define sz a[u].size()
#define bg a[u].begin()
#define pb push_back
#define F first
#define S second
using namespace std;
typedef long long ll;
const ll N=5e5+10;
vector<pair<ll,ll>>a[N];
ll f[N],n,k,x,y,z,w;
ll dfs(ll u,ll fa){
for(ll i=0;i<sz;i++)
if(a[u][i].S==fa)
{a[u].erase(bg+i); break;}
a[u].pb({0,u}); ll b=0;
sort(bg,a[u].end());
for(ll i=sz-1;i;i--){
ll t=dfs(a[u][i].S,u);
f[++x]=min(t,b);
b=max(t,b)+
a[u][i].F-a[u][i-1].F;
}
return b;
}
int main(){
scanf("%lld%lld",&n,&k);
for(ll i=1;i<n;i++){
scanf("%lld%lld",&x,&y);
scanf("%lld",&z),w+=z*2;
a[x].pb({z,y});
a[y].pb({z,x});
}
x=0,y=dfs(1,0),f[++x]=y;
sort(f+1,f+n+1);
for(ll i=n;i>n-k;i--)
printf("%lld\n",
w-(f[i]+=f[i+1]));
return 0;
}
:::
神秘卡常后即可多一个[黑题](https://www.luogu.com.cn/problem/P17851)。