zoukankan      html  css  js  c++  java
  • CF1223E Paint the Tree(树形DP)

    给出了一个由n个顶点组成的加权树。回想一下,树是一个没有圈的连通图。顶点ui和vi通过带权重wi的边连接。

    让我们将树的k-着色定义为每个顶点的k-着色,这样每个颜色的使用次数就不会超过两次。你可以假设你有无限多的颜色可用。我们说,如果一条边的端点共享至少一种颜色(即存在一种指定给两个端点的颜色),那么它在给定的k-着色中是饱和的。

    我们还将k-着色的值定义为饱和边的权重之和。

    请计算给定树的k-着色的最大可能值。

    你必须回答与q无关的问题。

    第一行包含一个整数q(1≤q≤5⋅105)-查询数。

    每个查询的第一行包含两个整数n和k(1≤n,k≤5⋅105)-树中的顶点数和分配给每个顶点的颜色数。

    /*
     * cf1223E
     * 题意:
     * 给出一棵树,选择若干条边使边权值和最大,要求每个节点至多被k条边覆盖
     * 题解:
     * 树形dp。
     * 考虑子节点和父节点的关系可知有两种情况:
     * (1)子节点已经连完k条边则不可以与父节点连边。
     * (2)子节点留一条边和父节点连边。
     * 可以用dp[0][u]表示选择k条当前节点与子节点的边得到的以u为节点的子树的最大值
     * dp[1][u]表示选择k-1条当前节点与子节点的边得到的以u为节点的子树的最大值,与子树相连的边可以用优先队列维护
     */
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=5e5+2;
    struct node {
        int u,v,next;
        ll w;
    }edge[maxn<<1];
    int head[maxn],tot;
    int N,K;
    ll dp[2][maxn],ans;
    void addedge (int u,int v,ll w) {
        edge[tot].u=u;
        edge[tot].v=v;
        edge[tot].w=w;
        edge[tot].next=head[u];
        head[u]=tot++;
    }
    inline void dfs (int u,int pre) {
        priority_queue<ll> q;
        ll x=0;
        for (int i=head[u];i!=-1;i=edge[i].next) {
            int v=edge[i].v;
            if (v==pre) continue;
            dfs(v,u);
            x+=dp[0][v];
            if (dp[1][v]+edge[i].w-dp[0][v]>0)
                q.push({dp[1][v]+edge[i].w-dp[0][v]});
        }
        ll w=1;
        while (!q.empty()&&w<K) {
            ll t=q.top();
            q.pop();
            x+=t;
            w++;
        }
        dp[0][u]=dp[1][u]=x;
        if (!q.empty()) dp[0][u]+=q.top();
        ans=max(ans,max(dp[1][u],dp[0][u]));
    }
    int main () {
        int Q;
        scanf("%d",&Q);
        while (Q--) {
            ans=0;
            tot=0;
    
            scanf("%d%d",&N,&K);
            for (int i=0;i<=N;i++) {
                dp[1][i]=0;
                dp[0][i]=0;
                head[i]=-1;
            }
            for (int i=1;i<N;i++) {
                int u,v;ll w;
                scanf("%d%d%lld",&u,&v,&w);
                addedge(u,v,w);
                addedge(v,u,w);
            }
            dfs(1,0);
            printf("%lld
    ",ans);
        }
    }

    接下来的n-1行中的每一行描述树的一个边。边i由三个整数ui、vi和wi(1≤ui,vi≤n,ui≠vi,1≤wi≤105)表示-它连接的顶点的标签和边的权重。可以保证给定的边形成一棵树。

    保证所有查询的n和不超过5⋅105。

    对于每个查询,打印一个整数-给定树的k-着色的最大值。

  • 相关阅读:
    angularIO 路由守卫
    vue-property-decorator用法
    windows mysql 忘记密码
    OSPF 做负载均衡
    NLB 部署网络负载平衡
    flexible.js 布局详解
    python setup.py 构建
    python Zope.interface安装使用
    lnmp菜单
    linux下的文件删除原理
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/12817722.html
Copyright © 2011-2022 走看看