zoukankan      html  css  js  c++  java
  • Accumulation Degree

    题目链接South Central China 2008 Accumulation Degree

    Description

    (给你一棵有n个结点的树,每一条边连接u_i和v_i)

    (流量为w_i,你需要找出一个结点最为root,并且求出从root出发到其他所有叶子结点的流量最大值)

    (数据范围1leq nleq 200000,并且sum n leq200000)

    Solution

    (如果你一来就想到网络流,说明你网络流没学好,树形dp相关的也没学好(笑))

    (我们要求出所有root中的最大值,毫无疑问肯定是要对每个结点都求一次的)

    (关键在于思考,如果对每一个点作为root去dfs跑他的子树,肯定超时。那么有没有什么方法状态转移)

    (在处理转移之前我们先维护一个root的最大流量,我们默认root为结点1,然后对他跑个dfs维护出flow[i])

    (flow[i]表示当前结点i所有子树流到流向他的值)

    (转移公式 sum_{所有子结点i} flow[p]+= min(w,flow[i]) 注:w为子结点到父节点的流量值,min是限流)

    无标题

    (在处理好以1为根结点的流量数组flow[]之后,我们来考虑向他的子结点转移)

    (观察上面这副图,假设当前结点为u,子结点为v,设某点的流量为f[i].)

    (则当前结点的最大流量 f[u] = x + min(y,z);)

    (其子结点的最大流量为f[v] = z+min(x,y);)

    (我们已知flow[u] = sum_{所有子结点i}flow[i])

    (那么f[u]-min(flow[v],w)就表示u子结点v以外子结点的流量贡献,也就是上图的x)

    (而子结点flow[v]即表示为上图的z,同时已知y即为w_{u->v})

    (所以可以得到f[v]=z+min(x,y)=flow[v]+min(f[u]-min(flow[v],w),w))

    (这样转移方程也就出来了)

    Code

    #include<bits/stdc++.h>
    typedef long long ll;
    #define IOS ios::sync_with_stdio(0); cin.tie(0);
    using namespace std;
    const int maxn = 200010;
    const int inf = 0x3f3f3f3f;
    //思路:从每一个叶子结点跑,然后维护出到当前点最小的值,作为该节点对叶子结点的贡献值
    struct node{
        int v; int w;
    };
    int deg[maxn];
    int sum[maxn];
    int sum1[maxn];
    vector<node>E[maxn];
    void dfs(int p,int fa){
        for(int i=0;i<(int)E[p].size();i++){
            int v = E[p][i].v; int w = E[p][i].w;
            if(v!=fa){
                dfs(v,p);
                if(deg[v] == 1){
                    sum[p] += w;
                }else{
                    sum[p] += min(w,sum[v]); 
                }
            }
        }
        return ;
    }
    void dfs1(int p,int fa){
        for(int i=0;i<(int)E[p].size();i++){
            int v = E[p][i].v; int w = E[p][i].w;
            if(v!=fa){
                if(deg[p] == 1){
                    sum1[v] = w;
                }else{
                    sum1[v] = sum[v] + min((sum1[p]- min(sum[v],w)),w);
                }
                dfs1(v,p);
            }
        }
    }
    int main(){
        IOS
        int T;
        cin>>T;
        while(T--){
            int n;
            cin>>n;
            for(int i=1;i<=n;i++) {
            	E[i].clear(),deg[i]=0;
            	sum1[i] = sum[i] = 0;
    		}
            for(int i=1;i<=n-1;i++){
                int u,v; int w;
                cin>>u>>v>>w;
                E[u].push_back((node){v,w});
                E[v].push_back((node){u,w});
                deg[u]++; deg[v]++;
            }
            dfs(1,0);
            sum1[1] = sum[1];
            dfs1(1,0);
            int ans = -inf;
            for(int i=1;i<=n;i++){
                ans = max(ans,sum1[i]);
            }
            cout<<ans<<endl;
        }
    }
    
  • 相关阅读:
    IIS卸载
    WebView个人总结
    在服务器解决get方法的乱码
    弹出小窗口,PopupWindow的使用
    调用系统的媒体音量控制显示
    自定义ImageButton,实现快进快退功能
    【原创】在Android系统下实现抓词
    解决android客户端显示中文乱码问题
    Tab添加左右按钮
    Ramdisk源代码详解
  • 原文地址:https://www.cnblogs.com/Tianwell/p/12724829.html
Copyright © 2011-2022 走看看