Accumulation Degree

Accumulation Degree

有一个有n个节点,n-1条河道的树形水系,每个河道有一个最大容水量(c[x][y])表示点x到y的最大容水量,源点可以源源不断出水,以源点作为根节点的树的叶子结点可以无限接纳水,而一个节点水的流量等于流过其儿子节点的水的流量之和,儿子节点水的流量不能超过其与父亲连边的最大容水量,询问最大的源点水流量,(nleq 2 imes 10^5)

显然为树形递推题,难点在根节点不定,不妨先枚举根节点,设(f[x])表示以x为根节点的子树中最大的水流量,不难有

[f[x]=sum_{yin son(x)}min(f[y],c[x][y]) ]

边界:叶子结点f无限大,其余为0

答案:f[r],r为根节点

但是因为枚举了根节点,时间复杂度为(O(n^2)),所以关键在解决根节点,而对于每个根节点求出来的信息,我们并没有充分利用,借着询问常用的维护的思想,不妨设(g[x])表示以x为根节点的最大水量,自然也就有

[g[x]=f[x]+min(g[y]-min(g[y],c[x][y]),c[x][y]) ]

于是求出随便一个根节点的f,然后求出所有g即可,其实这就是二次递推和换根法。

附录:

其实注意到叶子节点的特殊性,所以叶子节点的f的转移方程,需要直接转移边权,不进行大小比较,同样对于g的求法,也要判断第一次的根节点是否为叶结点,因为它不作为根节点时候,它的流量是无限大,同理当你要求的g为叶结点时,也要特判,因为此时用于转移g的节点,也就是它的父亲节点直接利用的f值为0,是不合法的,所以网上很多的代码求g时少特判一个叶子结点,所以叶子结点的g值求的是错的,但是答案显然是靠中间更优秀,于是是否特判也就无所谓了,所以以下的代码,也没有进行特判,难的为了学术的严谨,加一点常数,也告诉了我们,一道题目边界的重要性。

参考代码:

dfs:

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
#define intmax 0x7fffffff
using namespace std;
struct point{
    int next,to,w;
}ar[400005];int at;
bool check[200005];
int head[200005],f[200005],
    g[200005],out[200005];
il int min(int,int);
void dfs(int),root(int);
il void read(int&),link(int,int,int);
int main(){
    int lsy;read(lsy);
    while(lsy--){
        int n;read(n),at&=0;
        memset(f,0,sizeof(f));
        memset(g,0,sizeof(g));
        memset(out,0,sizeof(out));
        memset(head,0,sizeof(head));
        for(int i(1),j,k,w;i<n;++i)
            read(j),read(k),read(w),
                link(j,k,w),link(k,j,w),++out[j],++out[k];
        dfs(1),g[1]=f[1],root(1);int ans(0);
        for(int i(1);i<=n;++i)if(ans<g[i])ans=g[i];
        printf("%d
",ans);
    }
    return 0;
}
void root(int x){
    check[x]&=false;
    for(int i(head[x]);i;i=ar[i].next)
        if(check[ar[i].to]){
            if(out[x]==1)g[ar[i].to]=f[ar[i].to]+ar[i].w;
            else g[ar[i].to]=f[ar[i].to]+min(g[x]-min(ar[i].w,f[ar[i].to]),ar[i].w);//带了一些未解释的贪心
            /*else{
                if(out[ar[i].to]==1)
                    g[ar[i].to]=f[ar[i].to]+min(g[x]-ar[i].w,ar[i].w);
                else g[ar[i].to]=f[ar[i].to]+min(g[x]-min(ar[i].w,f[ar[i].to]),ar[i].w);
// 实际应该打法
                }*/
            root(ar[i].to);
        }
}
il int min(int a,int b){
    return a<b?a:b;
}
void dfs(int x){
    check[x]|=true;
    for(int i(head[x]);i;i=ar[i].next)
        if(!check[ar[i].to]){
            dfs(ar[i].to);
            if(out[ar[i].to]==1)f[x]+=ar[i].w;
            else f[x]+=min(f[ar[i].to],ar[i].w);
        }
}
il void link(int u,int v,int w){
    ar[++at].to=v,ar[at].w=w;
    ar[at].next=head[u],head[u]=at;
}
il void read(int &x){
    x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}

bfs

#include <iostream>
#include <cstdio>
#include <cstring>
#define il inline
#define ri register
#define intmax 0x7fffffff
using namespace std;
struct point{
    int next,to,w;
}ar[400005];int at;
bool check[200005];
int T[200005],head[200005],out[200005],n,
    f[200005],g[200005],pa[200005],w[200005];
il void read(int&),link(int,int,int),bfs(int);
template<class free>il free Min(free,free);
int main(){
    int lsy;read(lsy);
    while(lsy--){
        read(n),at&=0;
        memset(f,0,sizeof(f));
        memset(g,0,sizeof(g));
        memset(out,0,sizeof(out));
        memset(head,0,sizeof(head));
        memset(check,0,sizeof(check));
        for(int i(1),j,k,l;i<n;++i)
            read(j),read(k),read(l),
                link(j,k,l),link(k,j,l),
                ++out[j],++out[k];
        bfs(1);int ans(0);
        for(int i(1);i<=n;++i)if(g[i]>ans)ans=g[i];
        printf("%d
",ans);
    }
    return 0;
}
template<class free>
il free Min(free a,free b){
    return a<b?a:b;
}
il void bfs(int s){
    int h(0),t(1);T[1]=s;
    while(h<t){
        ++h,check[T[h]]|=true;
        for(int i(head[T[h]]);i;i=ar[i].next)
            if(!check[ar[i].to])
                T[++t]=ar[i].to,pa[ar[i].to]=T[h],
                    w[ar[i].to]=ar[i].w;
    }for(int i(n);i;--i){
        if(out[T[i]]==1)f[pa[T[i]]]+=w[T[i]];
        else f[pa[T[i]]]+=Min(f[T[i]],w[T[i]]);
    }
    g[1]=f[1];
    for(int i(2);i<=n;++i){
        if(out[pa[T[i]]]==1)g[T[i]]=f[T[i]]+w[T[i]];
        else g[T[i]]=f[T[i]]+min(g[pa[T[i]]]-min(w[T[i]],f[T[i]]),w[T[i]]);
    }
}
il void link(int u,int v,int w){
    ar[++at].to=v,ar[at].w=w;
    ar[at].next=head[u],head[u]=at;
}
il void read(int &x){
    x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
}

原文地址:https://www.cnblogs.com/a1b3c7d9/p/10927474.html