题目满足单调性,考虑先二分后进行check
对于check,用树形dp来表示状态是否可达,设计d[i][j]表示以j为根节点的子树,使用了i个a边,能满足长度不超过二分答案值的离i最远距离的最小值
含义就是,对于每种合法方案,都保存最小的距离,这样对之后的状态转移的最优的。
#includeusing namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pll; const int N=4e5+10; const int mod=1e9+7; const ll inf=1e18; int h[N],ne[N],e[N],w1[N],w2[N],idx; int n,k,sz[N]; ll f[25][200020]; ll ans[N]; void add(int a,int b,int x,int y){ e[idx]=b,ne[idx]=h[a],w1[idx]=x,w2[idx]=y,h[a]=idx++; } void dfs(int u,int fa,ll up){ sz[u]=1; int i; for(i=0;i<=20;i++) ans[i]=inf; f[0][u]=0; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa) continue; dfs(j,u,up); int op=min(k,sz[u]+sz[j]); for(int x=0;x<=op;x++) ans[x]=inf; for(int x=0;x<=min(k,sz[u]);x++){ for(int y=0;y<=min(k,sz[j]);y++){ if(x+y<=op&&f[x][u]+f[y][j]+w2[i]<=up){ ans[x+y]=min(ans[x+y],max(f[x][u],f[y][j]+w2[i])); } if(x+y+1<=op&&f[x][u]+f[y][j]+w1[i]<=up){ ans[x+y+1]=min(ans[x+y+1],max(f[x][u],f[y][j]+w1[i])); } } } sz[u]+=sz[j]; for(int x=0;x<=op;x++) f[x][u]=ans[x]; } } bool check(ll mid){ int i,j; for(i=0;i<=k;i++){ for(j=1;j<=n;j++) f[i][j]=inf; } dfs(1,-1,mid); return (f[k][1]<inf); } int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ cin>>n>>k; int i; for(i=1;i<=n;i++) h[i]=-1; ll l=1,r=0; for(i=1;i ){ int a,b,c,d; cin>>a>>b>>c>>d; add(a,b,c,d); add(b,a,c,d); r+=max(c,d); } while(l<r){ ll mid=l+r>>1; if(check(mid)) r=mid; else l=mid+1; } cout< endl; idx=0; } return 0; }