zoukankan      html  css  js  c++  java
  • [动态规划][换根] Codeforces 1292C Xenon's Attack on the Gangs

    题目大意

    现在有一棵 (n (2leq n leq 3000)) 个结点的树,每条边分配了一个 ([0,2]) 的整数权值 (w) , 所有分配的整数都是不同的,并且每个整数都能分配给某条边。

    定义: (S_{path(s,t)}=mex_{(u,v)in path(s,t)} w(u,v))
    要求最大化 (sumlimits_{1leq s < t leq n} S_{path(s,t)})

    题解

    考虑每条边的贡献,我们从0开始分配边权。
    假设我们令 (w(u_0,v_0)=0) , 令边 ((u_0,v_0)) 把树分成了两个点集, 其中含有 (u) 的点集的大小是 (Size(u_0)), 含有 (v_0) 的点集的大小是 (Size(v_0))。则令 (w(u_0,v_0)=0) 后,对于所有跨越 ((u_0,v_0)) 的路径,其 (mex) 都大于 (0),贡献是 (Size(u_0) imes Size(v_0))。然后我们去分配边权1,令 (w(u_1,v_1)=1),因为是 (mex),所以此时只对同时经过 ((u_0,v_0))((u_1,v_1)) 的边有贡献。显然,((u_1,v_1)) 应该与 ((u_0,v_0)) 相连才更优。以此类推,我们将最终把一条树链上的每条边分配边权,不在这条树链上的边给它分配边权也对答案没有贡献。且这条链上的边权一定是先减后增,否则易证答案不会更优。

    因为链上的边权是先减后增,所以每次是按边权从小到大给链的两端分配边权。这样的话和区间dp有点类似。设 (dp[u][v]) 表示已经给 (usim v) 这条树链分配了边权 (0sim l-1)所得到的最大答案。设(Size_{root}(u)) 表示以 (root) 为根时以 (u) 为根的子树的大小,(Fa_{root}(u)) 表示以 (root) 为根时 (u) 的父亲。那么(dp[u][v]=max(dp[u][Fa_u(v)],dp[Fa_v(u)][v])+Size_u(v) imes Size_v(u)) 。对于(Size_{root}(u))(Fa_{root}(u)),只要从每个点开始跑一遍DFS预处理即可,对于 (dp[u][v]) 记忆化搜索即可。时间复杂度 (O(n^2))

    Code

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    #include <map>
    using namespace std;
    
    #define RG register int
    #define LL long long
    
    template<typename elemType>
    inline void Read(elemType &T){
        elemType X=0,w=0; char ch=0;
        while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
        while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        T=(w?-X:X);
    }
    
    struct edge{int Next,to;};
    edge G[6010];
    int head[3010],Fa[3010][3010];
    LL Size[3010][3010],dp[3010][3010];
    int N,cnt=2;
    LL Ans=0;
    
    inline void Add_Edge(int u,int v){
        G[cnt].to=v;
        G[cnt].Next=head[u];
        head[u]=cnt++;
    }
    
    void DFS(int u,int fa,int root){
        Size[root][u]=1;
        for(int i=head[u];i;i=G[i].Next){
            int v=G[i].to;
            if(v==fa) continue;
            Fa[root][v]=u;
            DFS(v,u,root);
            Size[root][u]+=Size[root][v];
        }
        return;
    }
    
    LL DP(int u,int v){
        if(u==v) return 0;
        if(dp[u][v]) return dp[u][v];
        return dp[u][v]=max(DP(u,Fa[u][v]),DP(Fa[v][u],v))+Size[u][v]*Size[v][u];
    }
    
    int main(){
        Read(N);
        for(RG i=1;i<=N-1;++i){
            int u,v;
            Read(u);Read(v);
            Add_Edge(u,v);
            Add_Edge(v,u);
        }
        for(RG i=1;i<=N;++i)
            DFS(i,0,i);
        for(RG u=1;u<=N;++u)
            for(RG v=1;v<=N;++v)
                Ans=max(Ans,DP(u,v));
        printf("%I64d
    ",Ans);
        return 0;
    }
    
  • 相关阅读:
    ASP.NET AJAX Sys未定义的解决方法
    网页简繁体转换
    asp.net2.0中TreeView不刷新获得节点值
    异常详细信息: System.Runtime.InteropServices.COMException: 无效的类别字符串
    HDOJ1233 还是畅通工程[Prim算法||Kruskal算法]
    Kruskal/Prim/Dijkstra模板
    HDOJ3790 最短路径问题[Dijkstra算法||SPFA]
    HDOJ1285 确定比赛名次[拓扑排序]
    HDOJ1162 Eddy's picture[求最短路prim||kruskal算法]
    HDOJ1213 How Many Tables[并查集入门]
  • 原文地址:https://www.cnblogs.com/AEMShana/p/12695375.html
Copyright © 2011-2022 走看看