【JZOJ100003】【NOI2017模拟.4.1】 Tree

来源:互联网 发布:企业it数据基础设施 编辑:程序博客网 时间:2024/05/16 10:04

Description

这里写图片描述

Data Constraint

这里写图片描述

Solution

这是一道无源汇的网络流模型。
我们树边定义为从上往下流为正边,(流量为次数,费用为0),而路径定义从下往上流为正边(流量为1,费用为收益),这就构成了一个个环。我们先暴力的流一下,判断出每个节点流量的入度和出度。假如一个点的入度小于出度,我们就从源点往该点连一条流量为|in-out|,费用为0的边,否则该点往汇点连一条流量为|in-out|,费用为0的边,最后跑一遍费用流,答案即总收益-最消费用最大流。

Code

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>#define ll long longusing namespace std;const ll maxn=4e4+5;struct code{    ll a,b,c;}a[maxn];ll first[maxn],last[maxn],next[maxn],value[maxn],cost[maxn],in[maxn],out[maxn],deep[maxn],dui[maxn];ll n,m,i,t,j,k,l,x,y,z,p,num,ans,bz[maxn],d[maxn],q,ans1;void lian(ll x,ll y,ll z,ll k){    last[++num]=y;next[num]=first[x];first[x]=num;value[num]=z;cost[num]=k;}void dg(ll x,ll y){    ll t;deep[x]=deep[y]+1;    for (t=first[x];t;t=next[t]){        if (last[t]==y){            value[t]=0;continue;        }        dg(last[t],x);in[last[t]]+=value[t];out[x]+=value[t];    }}int pan(){    ll i,k=maxn*maxn*maxn,x,t;    if (!p) return 1;    for (x=0;x<=n;x++){        if (bz[x]!=p)continue;        for (t=first[x];t;t=next[t])            if (bz[last[t]]!=p && value[t]) k=min(k,d[last[t]]+cost[t]-d[x]);    }    if (k==maxn*maxn*maxn) return 0;    for (x=0;x<=n;x++)        if (bz[x]==p) d[x]+=k;    return 1;}ll dg1(ll x,ll sum){    ll t,k,q=sum;    if (x==n+1){        ans-=d[0]*sum;ans1+=sum;return sum;    }    bz[x]=p;    for (t=first[x];t;t=next[t]){        if (d[x]!=d[last[t]]+cost[t]||!value[t]||bz[last[t]]==p)continue;        k=dg1(last[t],min(q,value[t]));        if (k){            value[t]-=k;value[dui[t]]+=k;q-=k;            if (!q) break;        }    }    return sum-q;}int main(){    freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);    scanf("%lld",&q);    while (q){num=0;ans=0;memset(first,0,sizeof(first));        memset(in,0,sizeof(in));memset(out,0,sizeof(out));        scanf("%lld%lld",&n,&m);        for (i=1;i<n;i++)            scanf("%lld%lld%lld",&x,&y,&z),lian(x,y,z,0),lian(y,x,z,0);        dg(1,0);        for (i=1;i<=m;i++){            scanf("%lld%lld%lld",&x,&y,&z);ans+=z;            if (deep[x]<deep[y]) swap(x,y);            lian(x,y,1,z);lian(y,x,0,-z);            in[y]++;out[x]++;        }t=k=0;        for (i=1;i<=n;i++)            if (in[i]<out[i]){                lian(0,i,out[i]-in[i],0),lian(i,0,0,0);t++;            }            else if (in[i]>out[i]){                lian(i,n+1,in[i]-out[i],0),lian(n+1,i,0,0);k++;            }        for (i=1;i<=num;i++)            if (i%2)dui[i]=i+1,dui[i+1]=i;        p=0;memset(bz,0,sizeof(bz));memset(d,0,sizeof(d));ans1=0;        while (pan()){p++;            while (dg1(0,maxn))p++;        }        printf("%lld\n",ans);        q--;    }}
1 0