B3-F-Flow Finder(毒瘤dfs)

Problem

给出经过每个点的流量,0代表不确定,将整张图的各个点的流量输出,如果方案不唯一或者有的点最终流量<=0或者出现矛盾,输出impossible。

Solution

先确定叶子结点的流量,再向上确定其它结点的流量。记录每个点所能确定的其下叶子结点的总权值,如果其确定的叶子结点只有一个或确定的叶子结点数等于其能确定的总权值,就更新这部分叶子结点。
注意,一个叶子结点只由它最近的权值不为0的祖宗确定。

Code

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=3e5+5;
int n,last[maxn],cnt,fa[maxn],f[maxn];//num:底下未赋值叶子结点数
long long p[maxn],consts[maxn],num[maxn];
struct edge
{
    int v,next;
} e[maxn*2];
bool conf,islev[maxn];
inline void add(int u,int v)
{
    e[++cnt].v=v;
    e[cnt].next=last[u];
    last[u]=cnt;
}
void dfs(int u)
{
    long long pw=0;
    for(int i=last[u]; i; i=e[i].next)
    {
        int v=e[i].v;
        if(v==fa[u]) continue;
        dfs(v);
    }

    for(int i=last[u]; i; i=e[i].next)
    {
        int v=e[i].v;
        if(v==fa[u]) continue;
        if(p[v]) pw+=p[v];
    }
    if(p[u]==0)
        p[u]=pw;
    if(pw&&p[u]!=pw||p[u]<=0) conf=1;
}
int dfs2(int u)
{
    if(!islev[u])
    {
        if(!p[u])
            num[u]++;
        return p[u];
    }
    long long ans=0;
    for(int i=last[u]; i; i=e[i].next)
    {
        int v=e[i].v;
        if(v==fa[u]) continue;
        long long tmp=dfs2(v);
        if(!p[v])
        {
            ans+=tmp;
            num[u]+=num[v];
        }
        else ans+=p[v];
    }
    consts[u]=p[u]-ans;
    return ans;
}
int finds(int x)
{
    if(!x) return 0;
    return (x&&p[x])?x:f[x]=finds(f[x]);
}
int main()
{
    cin>>n;
    for(int i=2; i<=n; i++)
    {
        scanf("%d",&fa[i]);
        add(i,fa[i]);
        add(fa[i],i);
        islev[fa[i]]=1;
    }
    for(int i=1; i<=n; i++)
        f[i]=fa[i];
    for(int i=1; i<=n; i++)
        scanf("%d",&p[i]);
    dfs2(1);
    p[0]=0;
    for(int i=1; i<=n; i++)
    {
        if(!islev[i]&&!p[i])
        {
            int x=finds(i);
            if(!x) continue;
            if(num[x]==1)
                p[i]=consts[x];
            else if(consts[x]==num[x])
                p[i]=1;
        }
    }
    dfs(1);
    if(conf)
    {
        cout<<"impossible"<<endl;
        init();
        continue;
        return 0;
    }
    for(int i=1; i<=n; i++)
        cout<<p[i]<<endl;
    init();
}
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈希表扁豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值