HDU6769 In Search of Gold(树形DP+二分)
题意:
给出一棵树,每条边可以用a权值也可以用b权值。
你最多可以使k条边用a权值,剩余边用b权值。询问树的直径的最小值。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+100; const int K=25; typedef long long ll; int T,n,m; struct node { int u,v,a,b,nxt; }edge[maxn<<1]; int head[maxn],tot; void addedge (int u,int v,int a,int b) { edge[tot].u=u; edge[tot].v=v; edge[tot].a=a; edge[tot].b=b; edge[tot].nxt=head[u]; head[u]=tot++; edge[tot].u=v; edge[tot].v=u; edge[tot].a=a; edge[tot].b=b; edge[tot].nxt=head[v]; head[v]=tot++; } ll f[maxn][K],h[maxn],size[maxn],mid,l,r; void dfs (int x,int y){ size[x]=f[x][0]=0; for (int i=head[x];i!=-1;i=edge[i].nxt) { int u=edge[i].v; if (u==y) continue; dfs(u,x); int A=edge[i].a,B=edge[i].b,pre=size[x],cur=size[u],now=min(pre+cur+1,m); for (int j=0;j<=now;j++) h[j]=mid+1; for (int j=0;j<=pre;j++) for (int k=0;k<=cur&&j+k<=m;k++) { if (f[x][j]+f[u][k]+A<=mid) h[j+k+1]=min(h[j+k+1],max(f[x][j],f[u][k]+A)); if (f[x][j]+f[u][k]+B<=mid) h[j+k]=min(h[j+k],max(f[x][j],f[u][k]+B)); } size[x]=now; for (int j=0;j<=now;j++) f[x][j]=h[j]; } } int main () { scanf("%d",&T); while (T--) { scanf("%d%d",&n,&m); l=r=0; ll ans=0; for (int i=0;i<=n;i++) head[i]=-1;tot=0; for (int i=1;i<n;i++) { int x,y,A,B;scanf("%d%d%d%d",&x,&y,&A,&B);addedge(x,y,A,B); r+=max(A,B); } while (l<=r) { mid=(l+r)>>1;dfs(1,0); if (f[1][m]<=mid) { ans=mid;r=mid-1; } else { l=mid+1; } } printf("%lld\n",ans); } }