zoukankan      html  css  js  c++  java
  • 2019ICPC上海H-Tree Partition(二分+树上dp)

    题意:给定 n 个结点的树,结点带权,给定一个数 k,要求把这棵树分成 k 个部分,使得每部分的结点权值和中的最大值最小,求该最小值。

    解法:要使得最大值最小,所以需要二分枚举最大值lim,问题变成判断是否能划分出k-1个连通块使得最大值不超过lim,即判定划分连通块权值不超过lim的个数是否小于等于k,即割去的边数小于k。

    再对每一次check内部的树上dp来看,我们对于u作为根节点分析。他会有许多子节点v[i],我们对v[i]进行以[i]从小到大排序。看此时dp[u]能添加最多几个子节点dp[v]使得满足其≤limit,满足的话res就不变;超出的话就加其他没有添加进去的子节点的数量即可。

    总结:想法还是很中规中矩,感觉不太难。但是一时半会没想出来,可能是对于树上dp问题还是不太熟练造成的。

    #include<bits/stdc++.h>
    #pragma GCC optimize(2)
    #define ll long long
    #define rep(i,a,n) for(int i=a;i<=n;i++)
    #define per(i,n,a) for(int i=n;i>=a;i--)
    #define endl '
    '
    #define eps 0.000000001
    #define pb push_back
    #define mem(a,b) memset(a,b,sizeof(a))
    #define IO ios::sync_with_stdio(false);cin.tie(0);
    using namespace std;
    const int INF=0x3f3f3f3f;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    const int mod=1e9+7;
    const int maxn=2e5+5;
    ll val[maxn],dp[maxn];
    vector<int> G[maxn];
    int n,k;
    int dfs(int u,int fa,ll limit){
        vector<ll> sondp;
        dp[u]=val[u];
        int res=0;
        for(auto v:G[u]){
            if(v==fa) continue;
            res+=dfs(v,u,limit);
            sondp.pb(dp[v]);
        }
        sort(sondp.begin(),sondp.end());
        for(int i=0;i<sondp.size();i++){
            if(dp[u]+sondp[i]<=limit){
                dp[u]+=sondp[i];
            }else{
                res+=sondp.size()-i;
                break;
            }
        }
        return res;
    }
    bool check(ll lim){
        return dfs(1,-1,lim)<k;
    }
    int main(){
        int T;scanf("%d",&T);
        rep(cas,1,T){
            scanf("%d%d",&n,&k);
            rep(i,1,n-1){
                int u,v;scanf("%d%d",&u,&v);
                G[u].push_back(v);G[v].push_back(u);
            }        
            ll sum=0,mx=0;
            rep(i,1,n){
                scanf("%lld",&val[i]);
                sum+=val[i];
                mx=max(mx,val[i]);
            }
            ll l=mx,r=sum;
            while(l<r){
                ll mid=(l+r)>>1;
                if(check(mid)) r=mid;
                else l=mid+1;
            }
            printf("Case #%d: %lld
    ",cas,l);
            rep(i,1,n) G[i].clear(),dp[i]=0,val[i]=0;
        }
    }
    View Code
    Codeforces ID:Anonytt QQ: 847399102 可以添加&关注
  • 相关阅读:
    HDU 2544 最短路
    Codeforces Round #588 (Div. 2) D. Marcin and Training Camp
    Codeforces Round #590 (Div. 3) B2. Social Network (hard version)
    Codeforces Round #585 (Div. 2) B. The Number of Products
    MongoDB基本概念
    MongoDB基本命令
    MongoDB常见问题
    MongoDB副本集
    Zookeeper Java 客户端
    MongoDB安装
  • 原文地址:https://www.cnblogs.com/Anonytt/p/14584767.html
Copyright © 2011-2022 走看看