HDU6769 In Search of Gold(树形DP+二分)

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);
    }
}

 

posted @ 2020-09-23 18:44  zlc0405  阅读(220)  评论(0编辑  收藏  举报