zoukankan      html  css  js  c++  java
  • dtoj#4242. 大爷(w)&&CF1061E

    题目描述:

    这里有 $n$ 个节点和两位大爷,红大爷和蓝大爷。红大爷在坐在节点 $x$ 处,蓝大爷坐在节点 $y$ 处。然后他们各自画了 $n − 1$ 条边,形成了一棵红树和一棵蓝树。

    现在大爷们想选择一些节点激活,激活第 $i$ 个节点会带来 $w_i$ 的收益,但是因为两位大爷的树长得不一样,所以他们要先商量一番。

    两位大爷都分别开出了一些条件,条件是这样的,这位大爷画出的树上以该大爷所坐的节点为根,节点 $a_i$ 的子树中必须恰有 $b_i$ 个节点被激活。保证红大爷开出的条件中必存在$a_i = x$,同时蓝大爷开出的条件中必存在 $a_i = y$,不保证每位大爷开出的条件不会自相矛盾。如果没看懂请结合样例理解题意。

    现在大爷们把你抓了起来,问你能否找到一个方案满足所有的条件,如果存在,输出最大的收益,否则输出 $-1$。

    算法标签:费用流

    思路:

    考虑费用流,对于每一个点计算出最近能限制到我的节点

    S连向红大爷的树里有限制的点,流量为限制点数(要减去子树内其他点的限制),费用为 $0$ 。蓝大爷的树里有限制的点连向T。

    对于两颗树里的同一个节点,对于这个的节点在两棵树里限制自己的点之间连边,流量为 $1$ ,费用为 $-w[i]$ 。

    这样求最小费用流,如果能满流即存在答案,且答案为最小费用的相反数。否则无解。

    以下代码: 

    #include<bits/stdc++.h>
    #define il inline
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=1e3+5,inf=1e9;
    bool vis[N];
    int f[N<<3],c[N<<3],s1,s2,S,T,pre[N],ans,dis[N],w[N];
    int n,rt1,rt2,head[N],ne[N<<3],to[N<<3],cnt,g[N],lk[N];
    il int read(){
       int x,f=1;char ch;
       _(!)ch=='-'?f=-1:f;x=ch^48;
       _()x=(x<<1)+(x<<3)+(ch^48);
       return f*x;
    }
    il void ins(int x,int y){
        ne[++cnt]=head[x];
        head[x]=cnt;to[cnt]=y;
    }
    il int dfs(int x,int fa,int top){
        if(g[x])top=x;
        lk[x]=top;int res=0;
        for(int i=head[x];i;i=ne[i]){
            if(fa==to[i])continue;
            res+=dfs(to[i],x,top);
        }
        int tmp=g[x]?g[x]:res;
        if(g[x])g[x]-=res;
        if(g[x]<0){puts("-1");exit(0);}
        return tmp;
    }
    il void Add(int x,int y,int flow,int cost){
        ne[++cnt]=head[x];head[x]=cnt;
        to[cnt]=y;f[cnt]=flow;c[cnt]=cost;
    }
    il void add(int x,int y,int f,int c){
        Add(x,y,f,c);Add(y,x,0,-c);
    }
    il bool spfa(){
        for(int i=S;i<=T;i++)dis[i]=inf,vis[i]=0,pre[i]=-1;
        dis[S]=0;vis[S]=1;queue<int> q;q.push(S);
        while(!q.empty()){
            int x=q.front();q.pop();vis[x]=0;
            for(int i=head[x];i!=-1;i=ne[i]){
                if(dis[to[i]]>dis[x]+c[i]&&f[i]>0){
                    dis[to[i]]=dis[x]+c[i];pre[to[i]]=i;
                    if(!vis[to[i]])vis[to[i]]=1,q.push(to[i]);
                }
            }
        }
        return dis[T]<inf;
    }
    il void mcf(){
        while(spfa()){
            int mn=inf;
            for(int i=pre[T];i!=-1;i=pre[to[i^1]])
                mn=min(mn,f[i]);
            for(int i=pre[T];i!=-1;i=pre[to[i^1]])
                f[i]-=mn,f[i^1]+=mn;
            ans+=dis[T]*mn;s1-=mn;
        }
    }
    int main()
    {
        n=read();rt1=read();rt2=read()+n;
        for(int i=1;i<=n;i++)w[i]=read();
        for(int i=1;i<n;i++){
            int x=read(),y=read();
            ins(x,y);ins(y,x);
        }
        for(int i=1;i<n;i++){
            int x=read()+n,y=read()+n;
            ins(x,y);ins(y,x);
        }
        int Q=read(),a,b;
        while(Q--)a=read(),g[a]=read();
        Q=read();
        while(Q--)a=read()+n,g[a]=read();
        dfs(rt1,0,rt1);dfs(rt2,0,rt2);
        cnt=1;S=0;T=(n<<1)+1;
        for(int i=S;i<=T;i++)head[i]=-1;
        for(int i=1;i<=n;i++){
            if(g[i])add(S,i,g[i],0),s1+=g[i];
            if(g[i+n])add(i+n,T,g[i+n],0),s2+=g[i+n];
        }
        for(int i=1;i<=n;i++)add(lk[i],lk[i+n],1,-w[i]);
        if(s1^s2)return puts("-1"),0;mcf();
        if(s1)return puts("-1"),0;
        printf("%d
    ",-ans);
        return 0;
    }
    View Code
  • 相关阅读:
    bzoj3401[Usaco2009 Mar]Look Up 仰望*
    bzoj2021[Usaco2010 Jan]Cheese Towers*
    bzoj3767A+B Problem加强版
    bzoj3942[Usaco2015 Feb]Censoring*
    bzoj1673[Usaco2005 Dec]Scales 天平*
    bzoj3670[Noi2014]动物园
    stark——pop功能(admin中添加功能)
    stark——快速过滤list_filter
    stark——分页、search、actions
    stark——增删改页面
  • 原文地址:https://www.cnblogs.com/Jessie-/p/10527877.html
Copyright © 2011-2022 走看看