zoukankan      html  css  js  c++  java
  • bzoj2040 [2009国家集训队]拯救Protoss的故乡

    题目描述

    题解:

    大意是$0$为源,所有叶子节点为汇,求费用在$m$以内的最大流。

    直接跑网络流会$T$。

    考虑树形$dp$,发现自己不会。

    考虑贪心,每次找一个路径总费用最小的叶子结点(每条边费用为$0$或$1$或$inf$),然后求出路径最大容量,

    整条树链都减掉最大容量。

    输入时每条边有$(a,b)$,代表三种状态:

    费用为$0$,最大容量为$a$;

    费用为$1$,最大容量为$b$;

    费用为$inf$,最大容量$inf$。

    操作涉及到区间求最小值,区间减法,用树剖+线段树维护即可。

    貌似是$WC2019$讲的模拟费用流。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N = 10050;
    template<typename T>
    inline void read(T&x)
    {
        T f = 1,c = 0;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
        x = f*c;
    }
    ll m;
    int n,hed[N],cnt;
    struct EG
    {
        int to,nxt,a,b;
    }e[N];
    void ae(int f,int t,int a,int b)
    {
        e[++cnt].to = t;
        e[cnt].nxt = hed[f];
        e[cnt].a = a;
        e[cnt].b = b;
        hed[f] = cnt;
    }
    int dep[N],siz[N],fa[N],son[N],top[N],tin[N],tout[N],pla[N],tim,otd[N],A[N],B[N];
    struct Pair
    {
        ll x,y;
        Pair(){x=0x3f3f3f3f;}
        Pair(int x,int y):x(x),y(y){}
        void operator += (const int&a){x+=a;}
        bool operator < (const Pair&a){return x<a.x;}
    };
    struct segtree
    {
        ll tag[N<<2];
        Pair v[N<<2];
        void update(int u)
        {
            v[u] = v[u<<1]<v[u<<1|1]?v[u<<1]:v[u<<1|1];
        }
        void add(int u,int d)
        {
            v[u]+=d;
            tag[u]+=d;
        }
        void pushdown(int u)
        {
            if(tag[u])
            {
                add(u<<1,tag[u]);
                add(u<<1|1,tag[u]);
                tag[u] = 0;
            }
        }
        void insert(int l,int r,int u,int ql,int qr,ll d)
        {
            if(l==ql&&r==qr)
            {
                add(u,d);
                return ;
            }
            pushdown(u);
            int mid = (l+r)>>1;
            if(qr<=mid)insert(l,mid,u<<1,ql,qr,d);
            else if(ql>mid)insert(mid+1,r,u<<1|1,ql,qr,d);
            else insert(l,mid,u<<1,ql,mid,d),insert(mid+1,r,u<<1|1,mid+1,qr,d);
            update(u);
        }
        Pair query(int l,int r,int u,int ql,int qr)
        {
            if(l==ql&&r==qr)return v[u];
            pushdown(u);
            int mid = (l+r)>>1;
            if(qr<=mid)return query(l,mid,u<<1,ql,qr);
            else if(ql>mid)return query(mid+1,r,u<<1|1,ql,qr);
            else
            {
                Pair p1 = query(l,mid,u<<1,ql,mid);
                Pair p2 = query(mid+1,r,u<<1|1,mid+1,qr);
                return p1<p2?p1:p2;
            }
        }
        void build(int l,int r,int u,bool typ)
        {
            if(l==r)
            {
                if(!typ)//edge
                {
                    int x = pla[l];
                    if(A[x])v[u]=Pair(A[x],x);
                    else if(B[x]-A[x])v[u]=Pair(B[x]-A[x],x);
                    else v[u]=Pair(0x3f3f3f3f,x);
                }else//point
                {
                    int x = pla[l];
                    if(!otd[x])v[u] = Pair(0,x);
                    else v[u] = Pair(0x3f3f3f3f,x);
                }
                return ;
            }
            int mid = (l+r)>>1;
            build(l,mid,u<<1,typ);
            build(mid+1,r,u<<1|1,typ);
            update(u);
        }
    }tr0,tr1;
    void dfs1(int u,int f)
    {
        fa[u] = f;
        siz[u] = 1;
        dep[u] = dep[f]+1;
        for(int j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            dfs1(to,u);
            siz[u]+=siz[to];
            if(siz[to]>siz[son[u]])son[u]=to;
        }
    }
    void dfs2(int u,int Top)
    {
        top[u] = Top;tin[u]=++tim;pla[tim]=u;
        if(son[u])dfs2(son[u],Top);
        for(int j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            if(to!=son[u])
                dfs2(to,to);
        }
        tout[u]=tim;
    }
    Pair fd(int u)
    {
        Pair Min_Edge = tr0.query(1,n+1,1,tin[top[u]],tin[u]);
        u = fa[top[u]];
        while(u)
        {
            Pair tmp = tr0.query(1,n+1,1,tin[top[u]],tin[u]);
            Min_Edge = Min_Edge<tmp?Min_Edge:tmp;
            u = fa[top[u]];
        }
        return Min_Edge;
    }
    int zt[N];
    int main()
    {
        read(n),read(m);
        for(int f,t,a,b,i=1;i<=n;i++)
        {
            read(f),read(t),read(a),read(b);
            f++,t++;
            ae(f,t,a,b);otd[f]++;
            A[t]=a,B[t]=b;
        }
        dfs1(1,0),dfs2(1,1);
        tr0.build(1,n+1,1,0);
        tr1.build(1,n+1,1,1);
        for(int i=1;i<=cnt;i++)
        {
            int v = e[i].to;
            if(!e[i].a)tr1.insert(1,n+1,1,tin[v],tout[v],1),zt[v]=1;
            if(!e[i].b)tr1.insert(1,n+1,1,tin[v],tout[v],0x3f3f3f3f),zt[v]=2;
        }
        int ans = 0;
        while(1)
        {
            Pair now = tr1.query(1,n+1,1,1,n+1);
            int u = now.y;
            Pair Min_Edge = fd(u);
            ll d = Min_Edge.x;
            if(now.x)d=min(d,m/now.x);
            if(!d)break;
            m-=now.x*d;
            ans+=d;
            while(u)
            {
                tr0.insert(1,n+1,1,tin[top[u]],tin[u],-d);
                Pair tmp = tr0.query(1,n+1,1,tin[top[u]],tin[u]);
                while(!tmp.x)
                {
                    int v = tmp.y;
                    if(!zt[v])
                    {
                        tr0.insert(1,n+1,1,tin[v],tin[v],B[v]-A[v]);
                        tr1.insert(1,n+1,1,tin[v],tout[v],1);
                    }else if(zt[v]==1)
                    {
                        tr0.insert(1,n+1,1,tin[v],tout[v],0x3f3f3f3f);//
                        tr1.insert(1,n+1,1,tin[v],tout[v],0x3f3f3f3f);
                    }
                    zt[v]++;
                    tmp = tr0.query(1,n+1,1,tin[top[u]],tin[u]);
                }
                u = fa[top[u]];
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    uva 11729 Commando War
    剑指offer 38 数字在排序数组中出现的次数
    剑指offer 35 第一个只出现一次的字符
    剑指offer 33 把数组排成最小的数
    剑指offer17 合并两个排序的链表
    跳台阶
    app上线
    剑指offer54 表示数值的字符串
    剑指offer49 把字符串转换成整数
    段错误
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10416677.html
Copyright © 2011-2022 走看看