P8314 [COCI 2021/2022 #4] Parkovi 题解
最大值最小,容易想到二分。
考虑贪心,尽量选深度小的点,判断最少点数是否 \(\le k\)。对每个点记录子树内距离最近的公园和最远的未被覆盖的点。若两距离和 \(>mid\),则选择当前点,时间复杂度 \(\mathcal O(n\log V)\)。
参考代码:
#include<bits/stdc++.h>
#define ll long long
#define mxn 200003
#define pb push_back
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rept(i,a,b) for(int i=(a);i<(b);++i)
#define drep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
int n,k;
int tot,hd[mxn],vr[mxn<<1],ed[mxn<<1],nx[mxn<<1];
ll l,r,mid,d[mxn],f[mxn],d1[mxn],d2[mxn];
bool v[mxn];
inline void add(int x,int y,int z){
vr[++tot]=y,ed[tot]=z,nx[tot]=hd[x],hd[x]=tot;
}
void dfs(int x,int fa,ll ds){
f[x]=0;
ll mx=-1e18,mn=1e18;
for(int i=hd[x],y;i;i=nx[i])if((y=vr[i])!=fa){
dfs(y,x,ed[i]);
f[x]+=f[y];
mn=min(mn,d1[y]+ed[i]);
}
if(mn>mid)mx=0;
for(int i=hd[x],y;i;i=nx[i])if((y=vr[i])!=fa){
if(mn+d2[y]+ed[i]>mid)mx=max(mx,d2[y]+ed[i]);
}
if(mx+ds>mid){
f[x]++;
d1[x]=0,d2[x]=-1e18;
v[x]=1;
}else d1[x]=mn,d2[x]=mx;
}
signed main(){
scanf("%d%d",&n,&k);
for(int i=1,x,y,z;i<n;++i){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z),add(y,x,z);
}
r=2e14;
while(l<r){
mid=(l+r)>>1;
dfs(1,0,1e18);
if(f[1]<=k)r=mid;
else l=mid+1;
}
cout<<l<<'\n';
rep(i,1,n)v[i]=0;
mid=l,dfs(1,0,1e18);
rep(i,1,n)if(v[i])cout<<i<<" ",k--;
rep(i,1,n)if(!v[i]&&k)cout<<i<<" ",k--;
return 0;
}

浙公网安备 33010602011771号