[JZOJ1904] [2010]レスキュー話題のチームとプロトスの家

タイトル

効果の対象に

あなたのツリーネットワークを与え、各エッジは父親から息子を流します。ルート起源、シンク容量にリーフノードの流れは無限大です。
私たちは、拡大の合計まで、容量を拡張するために、いくつかのエッジを与えることができます\(m個\)の容量を。各側は容量制限があります。
最大のストリームの最大容量を拡張するために探しています。


歴史上のものがたり

漠然と推測正のソリューションは、チェーンツリー分割としなければならないが、再生できませんでしたが、プレイする時間がありません。
DPの暴力だけで湿気することができます。
セット\(H_ {I、J} \) の\は、(私は\)父親である\(Iは\)最大流量の、拡張\(J \)倍の容量。\(G_ {I、J} \) の\(Iは\)拡大する最大流量サブツリー\(J \)倍の容量。前者は後者の容量とエッジによって得られた最小値をとります。
伝達方程式は明らかです。
このように、水(\ 70 \)点、予想以上\(20 \)ポイント。


正解

費用流アプローチがあります:息子にそれぞれ異なる父のためにも、二つの側面を要しました。もう少しコストの同等いったん展開します。
最小コストの最大値、増補選挙費用の最小それぞれの道を実行して、それが以下で費用はかかりません\(m個\)最大流量が答えたときです。
このアプローチはある\(O(N ^ 2) \) 。各側が拡張した後、少なくとも完全な流れが存在することになるので、同等のこのエッジを削除しました。
解説所望のタイトルのスコアは\(\ 100) ...... ......しかし、私は本当に......以上に本当に、このような戦いを誰に仕え

正解は......費用流問題を最適化するためのプロパティツリーの使用による解説です\(LCT \)を、私は人々が、物流の問題に対する解決策をプレイ見すぎです。これはまた遊んで、明らかに、このような長いタイトルのためのコードの量です\(LCTを\)
次は費用流プロセスをシミュレートします:

  1. パスの葉ノードへのルートノードから最小限のコストを検索します。
  2. これは、最大流路取得\(F \) パスの最小側、すなわち容量)。
  3. 答えに統計。
  4. パスのすべての側面で容量が減算される(\のF \)
  5. 修飾された経路上の全流量(即ち、容量外を見ながら\(0 \)側)。カテゴリー話は:コストがある場合は、\(0 \) それはコスト変更\(1 \)を、そしてその容量を変更し、コストがされている場合(1 \)\(つまり、通過することができない、このエッジをマークし、すべての子孫)が到達することはできません。

もちろん、特別審査員を見て覚えていることよりも大きくしようとしている\(m個\)状況。

ツリーの分割及び鎖セグメントツリーを持つこの事は維持します。ツリーラインのメンテナンス情報:最小容量\(のF \)と彼の息子の数の\(NUMFの\) 上から最小容量の下端までのストリップのパス)だけでなく、最小コストの\(\ワット)とリーフノード番号\(numwの\) リーフ・ノード・パスと報酬へのルート・ノードのための料金)。
操作\(1 \)最小依頼することです\(W \)
操作\(2 \)現在のノードが最小のルートパスであり、\(F \)
操作\(4 \)現在のノードが保存するルート・パスである全てのエッジ間隔\(F \)
操作\(5 \)コストは、現在のノードのすべてのリーフノード間隔に追加することができている\(1 \)または無限。
これらの操作は、ある......


コード

ロング......幸い、木の分割と鎖セグメントツリー良い戦い......

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <cassert>
#define N 10010
#define INF 1000000000
int n,m;
struct EDGE{
    int to;
    EDGE *las;
} e[N];
int ne;
EDGE *last[N];
bool leaf[N];
int a[N],b[N];
int fa[N],siz[N],hs[N];
int top[N],dfn[N],nowdfn,to_num[N];
int noww[N];
void dfs1(int x){
    siz[x]=1;
    for (EDGE *ei=last[x];ei;ei=ei->las){
        fa[ei->to]=x;
        dfs1(ei->to);
        siz[x]+=siz[ei->to];
        if (siz[ei->to]>siz[hs[x]])
            hs[x]=ei->to;
    }
    if (siz[x]==1)
        leaf[x]=1;
}
void dfs2(int x,int t){
    top[x]=t;
    dfn[x]=++nowdfn;
    to_num[nowdfn]=x;
    if (hs[x])
        dfs2(hs[x],t);
    for (EDGE *ei=last[x];ei;ei=ei->las)
        if (ei->to!=hs[x])
            dfs2(ei->to,ei->to);
}
struct Node{
    int f,numf;
    int w,numw;
    int tagf,tagw;
} seg[N*4];
inline void updatef(int k){
    if (seg[k<<1].f<=seg[k<<1|1].f)
        seg[k].f=seg[k<<1].f,seg[k].numf=seg[k<<1].numf;
    else
        seg[k].f=seg[k<<1|1].f,seg[k].numf=seg[k<<1|1].numf;
}
inline void updatew(int k){
    if (seg[k<<1].w<=seg[k<<1|1].w)
        seg[k].w=seg[k<<1].w,seg[k].numw=seg[k<<1].numw;
    else
        seg[k].w=seg[k<<1|1].w,seg[k].numw=seg[k<<1|1].numw;
}
inline void pushdown(int k){
    if (seg[k].tagf){
        seg[k<<1].f+=seg[k].tagf;
        seg[k<<1|1].f+=seg[k].tagf;
        seg[k<<1].tagf+=seg[k].tagf;
        seg[k<<1|1].tagf+=seg[k].tagf;
        seg[k].tagf=0;
    }
    if (seg[k].tagw){
        if (seg[k].tagw>=INF)
            seg[k<<1].w=seg[k<<1|1].w=seg[k<<1].tagw=seg[k<<1|1].tagw=INF;
        else{
            seg[k<<1].w+=seg[k].tagw;
            seg[k<<1|1].w+=seg[k].tagw;
            seg[k<<1].tagw+=seg[k].tagw;
            seg[k<<1|1].tagw+=seg[k].tagw;
            seg[k].tagw=0;
        }
    }
}
void build(int k,int l,int r){
    if (l==r){
        if (leaf[to_num[l]])
            seg[k]={a[to_num[l]],to_num[l],0,to_num[l],0,0};
        else
            seg[k]={a[to_num[l]],to_num[l],INF,0,0,0};
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    updatef(k),updatew(k);
}
void changef(int k,int l,int r,int st,int en,int c){
    if (st<=l && r<=en){
        seg[k].f+=c;
        seg[k].tagf+=c;
        return;
    }
    pushdown(k);
    int mid=l+r>>1;
    if (st<=mid)
        changef(k<<1,l,mid,st,en,c);
    if (mid<en)
        changef(k<<1|1,mid+1,r,st,en,c);
    updatef(k);
}
void changew(int k,int l,int r,int st,int en,int c){
    if (st<=l && r<=en){
        if (c>=INF)
            seg[k].w=seg[k].tagw=INF;
        else{
            seg[k].w+=c;
            seg[k].tagw+=c;
        }
        return;
    }
    pushdown(k);
    int mid=l+r>>1;
    if (st<=mid)
        changew(k<<1,l,mid,st,en,c);
    if (mid<en)
        changew(k<<1|1,mid+1,r,st,en,c);
    updatew(k);
}
pair<int,int> un(const pair<int,int> &a,const pair<int,int> &b){return a.first<=b.first?a:b;}
pair<int,int> queryf(int k,int l,int r,int st,int en){
    if (st<=l && r<=en)
        return {seg[k].f,seg[k].numf};
    pushdown(k);
    int mid=l+r>>1;
    pair<int,int> res(INF,0);
    if (st<=mid)
        res=un(res,queryf(k<<1,l,mid,st,en));
    if (mid<en)
        res=un(res,queryf(k<<1|1,mid+1,r,st,en));
    return res;
}
int queryw(int k,int l,int r,int x){
    if (l==r)
        return seg[k].tagw;
    pushdown(k);
    int mid=l+r>>1;
    if (x<=mid)
        return queryw(k<<1,l,mid,x);
    return queryw(k<<1|1,mid+1,r,x);
}
inline int flow(int x){
    int res=INT_MAX;
    for (;x;x=fa[top[x]])
        res=min(res,queryf(1,1,n,dfn[top[x]],dfn[x]).first);
    return res;
}
inline void find(int x,int c){
    for (int y=x;y;y=fa[top[y]])
        changef(1,1,n,dfn[top[y]],dfn[y],-c);
    for (;x;x=fa[top[x]]){
        while (x){
            pair<int,int> tmp=queryf(1,1,n,dfn[top[x]],dfn[x]);
            if (tmp.first)
                break;
            if (noww[tmp.second]==0){
                noww[tmp.second]=1;
                changew(1,1,n,dfn[tmp.second],dfn[tmp.second]+siz[tmp.second]-1,1);
                changef(1,1,n,dfn[tmp.second],dfn[tmp.second],b[tmp.second]);
            }
            else{
                changew(1,1,n,dfn[tmp.second],dfn[tmp.second]+siz[tmp.second]-1,INF);
                x=fa[tmp.second];
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    a[1]=INT_MAX;
    for (int i=1;i<=n;++i){
        int u,v;
        scanf("%d%d",&u,&v);
        u++,v++;
        e[ne]={v,last[u]};
        last[u]=e+ne++;
        scanf("%d%d",&a[v],&b[v]);
        b[v]=min(b[v]-a[v],m);
    }
    n++;
    dfs1(1),dfs2(1,1);
    build(1,1,n);
    int ans=0;
    while (1){
        int x=seg[1].numw,cost=seg[1].w;
        if (cost>=INF)
            break;
        int plus=flow(x);
        if (m<cost*plus){
            ans+=m/cost;
            break;
        }
        m-=cost*plus;
        ans+=plus;
        find(x,plus);
    }
    printf("%d\n",ans);
    return 0;
}

概要

時には、ネットワークフローデータ構造を維持することができる......

おすすめ

転載: www.cnblogs.com/jz-597/p/11329599.html