Accumulation Degree - 树形dp

题目链接South Central China 2008 Accumulation Degree

Description

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

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

\(数据范围1\leq n\leq 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;
    }
}
posted @ 2020-04-18 11:29  Tianwell  阅读(154)  评论(0编辑  收藏  举报